You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨线程子窗口向父窗口传数据:VB.NET WPF程序挂起求助

问题分析与解决方案

核心问题

  1. 线程死锁:子窗口触发事件时,事件处理方法MyWinDataAvailable会在子窗口的线程中执行。此时你在方法内调用MyWin.MyData,而MyData的Get访问器使用了同步的Dispatcher.Invoke——这会要求子窗口线程处理该Invoke请求,但子线程此时正忙于执行事件处理方法,无法响应同步Invoke,最终导致程序挂起。
  2. 事件签名不匹配:子窗口声明的MyEvent(num As Integer)与父窗口事件处理方法MyWinDataAvailable(sender As Object)的参数完全不匹配,这会导致事件绑定和触发时的隐式错误。
  3. 线程入口方法参数错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 04:16:34