我为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()方法中收到followig错误:
跨线程操作无效:控制'labelConnectivityValue'从其创建的线程以外的线程访问。
1。我无法理解为什么我的代码被视为无效的跨线程操作。此外,我只是以相同的方式重新使用我之前在另一个WinForm应用程序中使用的代码。
2。我不知道如何解决这个问题,特别是考虑到我想要实现的目标看起来非常基本。
注意:statemanager中的代码只是一个定时器,它会经常检查连接状态,并在必须更改连接属性时触发事件,即连接状态是否已更改
答案 0 :(得分:3)
触发该事件的计时器或其他东西是从不同于拥有表单的程序(及其所有控件)执行的。
这可能在早期版本的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)
{
...
答案 1 :(得分:2)
我认为你问题的解决方案在于你写的最后一段。 你说你在StateManager中使用了一个Timer。
.NET框架中有三种常见的计时器:
前两个计时器正在使用Threads来完成他们的工作并且不是线程安全的。最后一个,Forms.Timer是在处理WinForms时使用计时器的首选方式。
您有两种选择: