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.我不知道该如何解决这个问题,尤其是考虑到我试图实现的目标似乎很基本

注意:状态管理器中的代码只是一个计时器,它每隔一段时间就会检查连接的状态,并在必须更改连接属性时触发事件,即如果连接状态已更改

C#-“;跨线程操作无效”;连接事件期间出错

触发该事件的计时器或诸如此类的东西是从与拥有表单(及其所有控件)的线程不同的线程执行的。

这可能在早期版本的WinForms中"起到了作用",因为现在抛出异常的显式检查不存在。然而,它没有正确地运行,这就是为什么添加这些检查,以帮助人们发现他们有问题。

有两种方法可以处理:

  1. 确保调用事件的代码没有使用辅助线程。你提到了一个定时器,可能是这个代码错误地使用了错误类型的定时器。你应该调查一下。

    如果代码使用的是System.Threading.Timer,请验证它是否可以改用System.Windows.Forms.Timer。第二个计时器使用Winforms系统所建立的消息传递系统,该系统将调用拥有表单及其控件的同一线程上的事件。

  2. 确保事件中的代码能够在不同的线程上执行

做到这一点的正确方法(即上面的第2点)是将每个调用封送到拥有表单及其控件的同一线程,您可以通过如下更改每个此类方法的头来做到这一步:

private void ConnectionHasChanged(object sender, ConnectionChangeEventArgs e)
{
    if (InvokeRequired)
    {
        Invoke(new Action(() =>
        {
            ConnectionHasChanged(sender, e);
        }));
        return;
    }
    if (e.ConnectionType == ConnectionType.Network)
    {
        ...

我认为你的问题的解决方案在于你写的最后一段。你说你在StateManager中使用计时器。

.NET框架中有三种常见的定时器:

  1. System.Timers.Timer(http://msdn.microsoft.com/en-us/library/system.timers.timer.aspx)
  2. System.Threading.Timer(http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx)
  3. System.Windows.Forms.Timer(http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx)

前两个计时器使用线程来完成它们的工作,并且不是线程安全的。最后一个,Forms.Timer是处理WinForms时使用计时器的首选方式。

你有两个选择:

  1. 请确保StateManager计时器是WinForm计时器
  2. 使用InvokeRequired方法:http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx了解你是否在正确的思路上