跨线程子窗口向父窗口传数据:VB.NET WPF程序挂起求助
问题分析与解决方案
核心问题
- 线程死锁:子窗口触发事件时,事件处理方法
MyWinDataAvailable会在子窗口的线程中执行。此时你在方法内调用MyWin.MyData,而MyData的Get访问器使用了同步的Dispatcher.Invoke——这会要求子窗口线程处理该Invoke请求,但子线程此时正忙于执行事件处理方法,无法响应同步Invoke,最终导致程序挂起。 - 事件签名不匹配:子窗口声明的
MyEvent(num As Integer)与父窗口事件处理方法MyWinDataAvailable(sender As Object)的参数完全不匹配,这会导致事件绑定和触发时的隐式错误。 - 线程入口方法参数错误:
ThreadStartingPoint声明了e As EventArgs参数,但启动线程时未传递任何参数,这会引发运行时异常。
修正后的代码
父窗口(MainWindow)
Public Class MainWindow Private MyWin As Window1 Private Sub BtnOpenWindow1_Click(sender As Object, e As RoutedEventArgs) Handles BtnOpenWindow1.Click Dim newWindowThread = New Thread(AddressOf ThreadStartingPoint) newWindowThread.SetApartmentState(ApartmentState.STA) newWindowThread.IsBackground = True newWindowThread.Start() btnSendData.IsEnabled = True BtnRequestData.IsEnabled = True BtnOpenWindow1.IsEnabled = False End Sub ' 移除多余的EventArgs参数,线程入口方法无需该参数 Private Sub ThreadStartingPoint() MyWin = New Window1 ' 绑定修正后的事件 AddHandler MyWin.DataAvailable, AddressOf MyWinDataAvailable MyWin.Show() Threading.Dispatcher.Run() End Sub ' 匹配事件签名,直接接收子窗口传递的数据 Private Sub MyWinDataAvailable(sender As Object, data As String) ' 仅需更新UI线程的控件,无需再读取子窗口属性 tbMainWindow.Dispatcher.Invoke(Sub() tbMainWindow.Text = data End Sub) End Sub Private Sub btnSendData_Click(sender As Object, e As RoutedEventArgs) Handles btnSendData.Click MyWin.MyData = tbMainWindow.Text End Sub Private Sub BtnRequestData_Click(sender As Object, e As RoutedEventArgs) Handles BtnRequestData.Click tbMainWindow.Text = MyWin.MyData End Sub End Class
子窗口(Window1)
Public Class Window1 Public Property MyData As String Get ' 若要保留该属性,可继续使用同步Invoke(仅在父线程主动请求时调用,无死锁风险) Return tbWindow1.Dispatcher.Invoke(Function() Return tbWindow1.Text End Function) End Get Set(value As String) tbWindow1.Dispatcher.Invoke(Sub() tbWindow1.Text = value End Sub) End Set End Property ' 使用标准事件签名,直接传递数据,避免后续跨线程读取 Public Event DataAvailable(sender As Object, data As String) Private Sub btnSendData1_Click(sender As Object, e As RoutedEventArgs) Handles btnSendData1.Click ' 直接在子线程获取控件文本(控件属于当前线程,无需Dispatcher) Dim currentData = tbWindow1.Text ' 触发事件并传递数据 RaiseEvent DataAvailable(Me, currentData) End Sub End Class
关键优化点
- 避免重复跨线程读取:子窗口触发事件时直接把当前数据传递给父窗口,无需父窗口再通过属性跨线程读取,从根源上避免死锁风险。
- 修正事件签名:遵循.NET标准事件模式(
sender As Object+ 数据参数),确保事件绑定和触发正常工作。 - 移除无效参数:修正线程入口方法的参数错误,避免运行时异常。
内容的提问来源于stack exchange,提问作者Scott8888
相关产品推荐
相关产品推荐

