.net - 从创建它的线程以外的线程访问的控件
问题描述
我想根据网络更改事件更新我的表单(VB.NET)上的一些标签。在一个事件中它工作得很好,但另一个引发了这个错误:
跨线程操作无效:控件“lblHostnameT”从创建它的线程以外的线程访问。
我正在编写一个用于网络诊断的小型应用程序。为了通知用户网络更改,我正在使用 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
}
}
推荐阅读
- c# - 如何在 Web API 中管理 POST 请求
- java - Avro - java.io.IOException:不是数据文件
- python - 为什么 ColumnTransformer 不调用 fit 它的变压器?
- javascript - 如何在 React JS 中应用动画
- twitter - Social Studio Radian6 获取推文数据
- python - 无法在烧瓶中使用 monogdb 运行 docker-compose
- java - 无法从数据库中检索数据(Firebase)
- ibm-mq - 我能否在仍使用 WAS 8.5.5 的同时将我的 MQ 版本升级到 9.0?
- r - 无法对下载按钮进行条件检查
- typescript - 打字稿推断方法的错误返回?