.net - 从不是在其上创建线程的线程访问的控件

标签 .net vb.net multithreading

我想基于网络更改事件更新表单(VB.NET)上的一些标签。在一个事件上,它可以完美运行,但另一个事件会引发此错误:

Cross-thread operation not valid: Control 'lblHostnameT' accessed from a thread other than the thread it was created on.



我正在编写一个用于网络诊断的小型应用程序。为了通知用户网络更改,我正在使用NetworkChange类。

在表单加载时,将创建事件处理程序:
AddHandler NetworkChange.NetworkAvailabilityChanged, AddressOf NetworkAvailabilityChanged
AddHandler NetworkChange.NetworkAddressChanged, AddressOf NetworkAddressChanged

这些是事件处理程序:
Private Sub NetworkAvailabilityChanged(sender As Object, e As NetworkAvailabilityEventArgs)
    ResetStats()
    niTray.ShowBalloonTip(5000)
End Sub

Private Sub NetworkAddressChanged(sender As Object, e As EventArgs)
    ResetStats()
    niTray.ShowBalloonTip(5000)
End Sub

这是ResetStats:
Private Sub ResetStats()
    lblHostnameT.Text = "[na]"
    lblIPT.Text = "[na]"
    lblGWT.Text = "[na]"
    lblDNST.Text = "[na]"
    lblGWPingT.Text = "[na]"
    lblDNSTestT.Text = "[na]"
    lblDCPingT.Text = "[na]"
    lblExtPingT.Text = "[na]"
    GWPingSent = 0
    GWPingReceived = 0
    GWAverage = 0
    DNSTestDone = 0
    DNSTestOK = 0
    DCPingSent = 0
    DCPingReceived = 0
    DCAverage = 0
    ExtPingSent = 0
    ExtPingReceived = 0
    ExtAverage = 0
    DCList.Clear()
    DCList.Add("192.168.19.113")
    DCList.Add("172.31.0.2")
    DCList.Add("172.31.0.3")
    DCList.Add("172.31.0.4")
    ExtList.Clear()
    ExtList.Add("www.google.com")
    ExtList.Add("www.msn.com")
    ExtList.Add("www.yahoo.com")
    DNSTestList.Clear()
    DNSTestList.Add("www.google.com")
    DNSTestList.Add("www.msn.com")
    DNSTestList.Add("www.yahoo.com")
    DNSTaskList.Clear()
    IPList.Clear()
    GWList.Clear()
    DNSList.Clear()
    lblHostnameT.Text = My.Computer.Name

    Dim nics() As NetworkInterface = NetworkInterface.GetAllNetworkInterfaces
    Dim ipi As IPInterfaceProperties

    For Each nic As NetworkInterface In nics
        If (nic.OperationalStatus = OperationalStatus.Up) AndAlso (nic.NetworkInterfaceType <> NetworkInterfaceType.Loopback) Then
            ipi = nic.GetIPProperties()
            If (ipi IsNot Nothing) AndAlso (ipi.UnicastAddresses IsNot Nothing) AndAlso (ipi.UnicastAddresses.Count > 0) Then
                For Each iip As IPAddressInformation In ipi.UnicastAddresses
                    If iip.Address.AddressFamily = Net.Sockets.AddressFamily.InterNetwork Then
                        IPList.Add(iip.Address.ToString & " (" & nic.Name & ")")
                    End If
                Next
                If (ipi.GatewayAddresses IsNot Nothing) AndAlso (ipi.GatewayAddresses.Count > 0) Then
                    For Each iip As GatewayIPAddressInformation In ipi.GatewayAddresses
                        If iip.Address.AddressFamily = Net.Sockets.AddressFamily.InterNetwork Then GWList.Add(iip.Address.ToString)
                    Next
                End If
                If (ipi.DnsAddresses IsNot Nothing) AndAlso (ipi.DnsAddresses.Count > 0) Then
                    For Each iip As Net.IPAddress In ipi.DnsAddresses
                        If iip.AddressFamily = Net.Sockets.AddressFamily.InterNetwork Then DNSList.Add(iip.ToString)
                    Next
                End If
            End If
        End If
    Next
    lblIPT.Text = String.Join(", ", IPList.ToArray)
    niTray.Text = "NetInfo" & vbCrLf & lblHostnameT.Text & vbCrLf & lblIPT.Text
    lblGWT.Text = String.Join(", ", GWList.ToArray)
    If GWList.Count > 1 Then
        lblGWT.ForeColor = Color.Red
    Else
        lblGWT.ForeColor = Drawing.SystemColors.ControlText
    End If
    lblDNST.Text = String.Join(", ", DNSList.ToArray)
End Sub

当我更改一个NIC的连接性时(例如通过切换WiFi SSID),将触发NetworkAvailabilityChanged并更新UI。但是当我进行更改导致调用NetworkAddressChanged时(例如通过将以太网电缆插入笔记本电脑),应用程序崩溃并在ResetStats的第一行显示错误。怎么了

最佳答案

UI控件具有线程关联性;您只能从UI线程触摸它们。您的网络事件不是来自UI线程。解决方案是将UI工作反弹到UI线程。在C#中,这将类似于:

// not shown prep work to figure out what to do
// string newLabel = ...
this.Invoke((MethodInvoker) delegate {
    // now we're on the UI thread
    someControl.Text = newLabel;
    // etc
});

很抱歉,我的VB不够强大,无法翻译。

如有疑问,您可以将整个内容弹回UI线程,但是对辅助线程进行预处理通常很有意义。但:

private void NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs args)
{
    if (InvokeRequired)
    {
        Invoke((MethodInvoker)delegate { // jump to UI thread
            NetworkAvailabilityChanged(sender, args);
        });
    }
    else
    {
        // the real code
    }
}

关于.net - 从不是在其上创建线程的线程访问的控件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57266520/

相关文章:

.net - Nunit Gui 测试结构中的分组方法

python - Visual Basic 开发人员想要编写 Linux 应用程序

c# - ASP.NET + 线程感知非托管 API

C++11:atomic::compare_exchange_weak 是否支持非原始类型?

c# - 访问项目资源中的图像?

.net - SimpleMembership 会取消用户身份验证?

wpf - 在 VB.net 代码隐藏中将 WPF RepeatBehavior 设置为 "none"

c# - 缺少非捕获 Task.Yield 迫使我使用 Task.Run,​​为什么要遵循它?

c# - 使用 NetComm dll 发送屏幕截图到主机

c# - 可变类型的不可变 View