跨线程错误:使用计时器释放窗体

5

我在一个Windows表单上设置了一个10秒的计时器。对于OnTimedEvent,我设置了在时间到达后该窗体被处理。然而,出现了以下错误:

InvalidOperationException被用户代码未处理。

非法跨线程操作:从创建它的线程以外的线程访问控件“notificationForm”。

错误出现在以下行:

protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

我定时器事件的代码如下:

    private void OnTimedEvent(object source, ElapsedEventArgs e)
    {
        this.Dispose();
    }

有人知道怎么修复这个问题吗?谢谢!

4个回答

5

看起来你正在使用 System.Timers.Timer

尝试改用 System.Windows.Forms.Timer 并订阅 Tick 事件。

如果必须使用该计时器,可以尝试将代码更改为以下内容:

private void OnTimedEvent(object source, ElapsedEventArgs e)
{
   this.BeginInvoke((MethodInvoker)delegate { this.Dispose(); });
}

嗨,感谢您的回复。我想知道System.Windows.Forms.Timer与普通计时器之间的区别是什么? - Thomas
1
Timers.Timer是一个基于服务器的计时器,这就是为什么它在不同的线程上而不是你的表单上。Windows计时器在与GUI相同的线程上运行--这就是为什么对于winforms应用程序来说,它通常是更合适的计时器。工具箱中的计时器是Forms.Timer。 - LarsTech

1

或者只是:

this.Invoke((Action)(() => { this.Dispose(); }));

你可以用一行代码实现这个功能:
timer1.Tick += (_, __) => { this.Invoke((Action)(() => { this.Dispose(); })); };

1
正如其他人所说,问题在于您的计时器正在运行一个线程,并试图处理在另一个线程上创建的对象。在尝试访问该对象之前,您需要在窗体上调用dispose方法。
需要注意的基本事项是,如果您尝试从另一个线程更改在设计器中创建的演示对象,则需要检查是否需要调用invoke。
void OnTick()
{
    if (InvokeRequired)
        Invoke(new MethodInvoker(OnTick));
    else
    {
        Dispose();
    }
}

1
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
    this.Invoke(new Action(() => this.Dispose()));
}

这个代码本身就可以工作


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接