由于不拥有线程,SerialPort读取会导致错误

awe*_*awe 2 .net vb.net wpf serial-port

我有一个简单的WPF Windows应用程序试图读取串口System.IO.Ports.SerialPort.

当我尝试读取DataReceived事件中的传入数据时,我得到一个异常,说我无法访问该线程.我该如何解决?

我在WPF窗口类中有这个:

Public WithEvents mSerialPort As New SerialPort()
Private Sub btnConnect_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnConnect.Click
    With mSerialPort
        If .IsOpen Then
            .Close()
        End If
        .BaudRate = 4800
        .PortName = SerialPort.GetPortNames()(0)
        .Parity = Parity.None
        .DataBits = 8
        .StopBits = StopBits.One
        .NewLine = vbCrLf

        .Open()
    End With
End Sub

Private Sub mSerialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles mSerialPort.DataReceived
    If e.EventType = SerialData.Chars Then
        txtSerialOutput.Text += mSerialPort.ReadExisting()
    End If
End Sub

Protected Overrides Sub Finalize()
    If mSerialPort.IsOpen Then
        mSerialPort.Close()
    End If
    mSerialPort.Dispose()
    mSerialPort = Nothing
    MyBase.Finalize()
End Sub
Run Code Online (Sandbox Code Playgroud)

DataReceived事件触发时,我得到以下异常mSerialPort.ReadExisting():

System.InvalidOperationException was unhandled
  Message="The calling thread cannot access this object because a different thread owns it."
  Source="WindowsBase"
  StackTrace:
       at System.Windows.Threading.Dispatcher.VerifyAccess()    at System.Windows.Threading.DispatcherObject.VerifyAccess()    at System.Windows.DependencyObject.GetValue(DependencyProperty dp)    at System.Windows.Controls.TextBox.get_Text()    at Serial.Serial.mSerialPort_DataReceived(Object sender, SerialDataReceivedEventArgs e) in D:\SubVersion\VisionLite\Serial\Serial.xaml.vb:line 24    at System.IO.Ports.SerialPort.CatchReceivedEvents(Object src, SerialDataReceivedEventArgs e)    at System.IO.Ports.SerialStream.EventLoopRunner.CallReceiveEvents(Object state)    at System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)    at System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal(_ThreadPoolWaitCallback tpWaitCallBack)    at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)
Run Code Online (Sandbox Code Playgroud)

小智 7

欢迎来到多元化的神奇世界!

发生的事情是,所有UI元素(类实例)只能由UI线程访问/更新.我不会详细介绍这个线程关联,但它是一个重要的主题,你应该检查一下.

数据进入串行端口的事件发生在与UI线程不同的线程上.UI线程有一个消息泵来处理Windows消息(如鼠标点击等).您的串行端口不会发送Windows消息.当数据进入串行端口时,将使用与UI线程完全不同的线程来处理该消息.

因此,在您的应用程序中,mSerialPort_DataReceived方法在与您的UI线程不同的线程中执行.您可以使用"线程"调试窗口来验证这一点.

当您尝试更新UI时,您尝试从另一个线程修改具有线程关联性的UI线程控件,这会引发您看到的异常.

TL; DR:您正在尝试修改UI线程之外的UI元素.使用

txtSerialOutput.Dispatcher.Invoke
Run Code Online (Sandbox Code Playgroud)

在UI线程上运行更新. 这里有一个关于如何在此页面的社区内容中执行此操作的示例.

Dispatcher将在UI线程上调用您的方法(它向UI发送一条窗口消息,说"Hai guize,运行此方法kthx"),然后您的方法可以安全地从UI线程更新UI.

  • 所有Windows窗体控件都有一个名为InvokeRequired的属性和一个名为Invoke的方法.它们与Dispatcher在WPF中执行的操作相同.只需谷歌两个术语,你会发现很多关于这个主题的文档. (2认同)