Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用MVP在线程上运行的串行端口_C#_Multithreading_User Interface_Serial Port_Mvp - Fatal编程技术网

C# 使用MVP在线程上运行的串行端口

C# 使用MVP在线程上运行的串行端口,c#,multithreading,user-interface,serial-port,mvp,C#,Multithreading,User Interface,Serial Port,Mvp,我有一个名为SerialClient的类,它通过串行端口发送/接收字节。调用SerialClient.Start()时,它进入无限while循环,直到调用SerialClient.Stop()。该类有一些属性,为了简单起见,比如说SerialClient.PropA,SerialClient.PropB 我需要在GUI中使用它。在GUI上,您可以调用Start、Stop并在属性更改时读取它们 为了在GUI中使用它,显然SerialClient需要在线程中操作,因为它是一个无止境的循环。因此,我用

我有一个名为
SerialClient
的类,它通过串行端口发送/接收字节。调用
SerialClient.Start()
时,它进入无限while循环,直到调用
SerialClient.Stop()
。该类有一些属性,为了简单起见,比如说
SerialClient.PropA
SerialClient.PropB

我需要在GUI中使用它。在GUI上,您可以调用Start、Stop并在属性更改时读取它们

为了在GUI中使用它,显然
SerialClient
需要在线程中操作,因为它是一个无止境的循环。因此,我用属性设置了视图,以匹配
SerialClient
的属性。视图在演示者上调用
Start()
Stop()

在presenter中,我创建了一个新线程,并对
SerialClient
的对象调用start。问题是当_serialClient抛出异常时,演示者无法捕获它,而且如果(
serialClient.PropB
)等属性发生更改并调用其更改的事件处理程序,则需要在GUI线程上调用它们。我尝试使用后台工作程序,但无法使其工作(更改属性仍然会从非UI线程影响UI)

一定有一个简单的解决办法,我正在寻找。GUI只需要调用方法和读取属性,并防止异常使整个应用程序崩溃


有什么想法吗?

您遇到了在C#中处理多线程应用程序时常见的两个问题:

  • 在后台线程中处理异常。当异常发生在后台线程中时,它们沿着堆栈向上移动,从一个调用方到另一个调用方,以查看是否有人能够捕获该异常。如果原始调用发生在您自己的调用之外(例如,来自串行端口或计时器的回调),您可能会收到异常通知,也可能不会收到异常通知。作为一个典型的解决方案,我所看到的是在一个try-catch中封装可以引发异常的代码,并让事件处理程序将异常推送到一个能够适当处理异常的线程(日志、通知用户、终止,所有这些)

  • 事件总是在调用它们的线程上执行。您必须使用Dispatcher和Invoke手动整理对UI线程的调用。我发现最简洁的代码是


  • ?您是否正在处理.Net SerialPort类上的ErrorReceived和DataReceived?如果是,则在SerialClient类中没有。有一个OpenCOM()方法。这将在COM5上创建一个设置正确的串行端口(_comport),然后将其打开。所有这些都在Start()中,调用OpenCOM(),然后在SendReceivedData方法上创建一个新线程,该方法包含无止境循环。在这里,我循环读取_comport.BytesToRead,如果有数据,则循环读取_comport.Read(/*Read-In-data here*/),如果有数据要发送,则循环写入(/*my-data here*/)。是的,要读取字节,请不要使用循环,只要尝试使用DataReceived事件和ErrorReceived,如果可以,然后,当serialport调用DataReceived时,您可以读取所有数据并调用委托。谢谢!我会试试看。但我有两个问题。1) 谁应该启动线程?它应该在演示者中完成,还是应该由SerialClient.Start()负责创建线程。2) 如果com端口中发生错误,即断电中断连接,COM5不存在,这些抛出异常而不是ErrorReceived事件。这些将不会被UI线程捕获并使应用程序崩溃。我需要向UI引发异常以通知用户。例如,“您选择的COM端口正被另一个应用程序使用”。我认为我需要使用ISynchronizeInvoke来处理此问题,但它在Compact Framework中不可用。代码库必须独立于GUI,因此我无法通过包含控件来破解解决方案。唯一的方法是在使用Compact Framework时为所有内容编写调用处理程序,我已经做了这个更改。我有start方法,它包含启动线程的代码,这样其他人的APi就更容易了。然后我有一个叫做Exception的事件。当引发将转义线程化方法的异常时,将调用此函数。通过这种方式捕获并停止异常,线程停止并引发事件。我认为这是最好的解决办法,但我真的认为有更好的方法。我已经研究过如何调用GUI线程,但是所需的接口不在紧凑的框架中。
    Thread thread = new Thread(_serialClient.Start);
    thread.IsBackground = true;
    thread.Start();
    
    
     void someEvent_Handler(object sender, SomeEventEventArgs e)
    {
        if (this.Dispatcher.CheckAccess())
        {
            // do work on UI thread
        }
        else
        {
            // or BeginInvoke()
            this.Dispatcher.Invoke(new Action(someEvent_Handler), 
                sender, e);
        }
    }