我有一个名为SerialClient
的类,它通过串行端口发送/接收字节。调用SerialClient.Start()
时,它会进入无限循环,直到调用SerialClient.Stop()
为止。该类有一些属性,为简单起见,我们可以说SerialClient.PropA
,SerialClient.PropB
。
我需要在GUI中使用它。在GUI上,您可以调用Start,Stop并在更改时读取属性。
为了在GUI中使用它,显然SerialClient
需要在一个线程中运行,因为它是一个无限循环。因此,我设置了视图,其属性与SerialClient
的属性相匹配。该视图会在演示者上调用Start()
和Stop()
。
在演示者中,我创建了一个新线程,并在SerialClient
的对象上调用start。问题是当_serialClient抛出异常时,演示者无法捕获它,并且如果像(SerialClient.PropB
)这样的属性更改并调用其更改的事件处理程序,则需要在GUI线程上调用它们。我尝试使用后台工作程序,但无法使其正常工作(更改属性仍然从非UI线程中获取UI)。
Thread thread = new Thread(_serialClient.Start);
thread.IsBackground = true;
thread.Start();
我一直在寻找一个简单的解决方案。 GUI只需要调用方法和读取属性,并防止异常崩溃整个应用程序。
有什么想法吗?
答案 0 :(得分:1)
您遇到了在C#中处理多线程应用程序时常见的两个常见问题:
处理后台线程中的异常。当后台线程中发生异常时,它们向上移动堆栈,从调用者到调用者,以查看是否有人能够捕获该异常。如果原始呼叫是从您自己的呼叫之外发生的(例如,从串行端口或定时器回调),您可能会或可能不会收到异常通知。作为一个典型的解决方案,我所看到的是在try-catch中包装可以抛出异常的代码,并让事件处理程序将异常推送到能够正确处理异常的线程(log,通知用户,终止,以上所有)
事件总是在调用它们的线程上执行。您必须使用Dispatcher和Invoke手动编组对UI线程的调用。我找到的最简单的代码就是here
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);
}
}