C#-“;跨线程操作无效”;连接事件期间出错
本文关键字:事件 连接 出错 无效 线程 操作 C#- | 更新日期: 2023-09-27 18:21:32
我为我的WinForm应用程序写了一点代码,通过更改颜色编码的标签控件来显示它运行的计算机的连接状态。
在我的表格中,我有以下代码:
public frmShell()
{
InitializeComponent();
this.stateManager = new StateManager();
}
private void frmShell_Load(object sender, EventArgs e)
{
// Subscribe to events
this.stateManager.ConnectionChange += new StateManager.ConnectionChangeHandler(ConnectionHasChanged);
}
private void ConnectionHasChanged(object sender, ConnectionChangeEventArgs e)
{
if (e.ConnectionType == ConnectionType.Network)
{
if (e.ConnectionState == ConnectionState.Connected)
{
SetLabelOnline();
}
else
{
SetLabelOffline();
}
}
}
private void SetLabelOffline()
{
labelConnectivityValue.Text = "Offline";
labelConnectivityValue.ForeColor = Color.Red;
}
private void SetLabelOnline()
{
labelConnectivityValue.Text = "Online";
labelConnectivityValue.ForeColor = Color.Green;
}
每次我禁用网络适配器来测试代码时,我都会在SetLabelOnline()或SetLabelOffline()方法中得到以下错误:
跨线程操作无效:控件"labelConnectivityValue"是从创建它的线程以外的线程访问的。
1.我不明白为什么我的代码会被认为是无效的跨线程操作。此外,我只是以完全相同的方式重新使用我之前在另一个WinForm应用程序中使用的代码
2.我不知道该如何解决这个问题,尤其是考虑到我试图实现的目标似乎很基本
注意:状态管理器中的代码只是一个计时器,它每隔一段时间就会检查连接的状态,并在必须更改连接属性时触发事件,即如果连接状态已更改
触发该事件的计时器或诸如此类的东西是从与拥有表单(及其所有控件)的线程不同的线程执行的。
这可能在早期版本的WinForms中"起到了作用",因为现在抛出异常的显式检查不存在。然而,它没有正确地运行,这就是为什么添加这些检查,以帮助人们发现他们有问题。
有两种方法可以处理:
-
确保调用事件的代码没有使用辅助线程。你提到了一个定时器,可能是这个代码错误地使用了错误类型的定时器。你应该调查一下。
如果代码使用的是System.Threading.Timer,请验证它是否可以改用System.Windows.Forms.Timer。第二个计时器使用Winforms系统所建立的消息传递系统,该系统将调用拥有表单及其控件的同一线程上的事件。
- 确保事件中的代码能够在不同的线程上执行
做到这一点的正确方法(即上面的第2点)是将每个调用封送到拥有表单及其控件的同一线程,您可以通过如下更改每个此类方法的头来做到这一步:
private void ConnectionHasChanged(object sender, ConnectionChangeEventArgs e)
{
if (InvokeRequired)
{
Invoke(new Action(() =>
{
ConnectionHasChanged(sender, e);
}));
return;
}
if (e.ConnectionType == ConnectionType.Network)
{
...
我认为你的问题的解决方案在于你写的最后一段。你说你在StateManager中使用计时器。
.NET框架中有三种常见的定时器:
- System.Timers.Timer(http://msdn.microsoft.com/en-us/library/system.timers.timer.aspx)
- System.Threading.Timer(http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx)
- System.Windows.Forms.Timer(http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx)
前两个计时器使用线程来完成它们的工作,并且不是线程安全的。最后一个,Forms.Timer是处理WinForms时使用计时器的首选方式。
你有两个选择:
- 请确保StateManager计时器是WinForm计时器
- 使用InvokeRequired方法:http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx了解你是否在正确的思路上