Winform控件和线程

时间:2016-10-20 14:25:06

标签: c# winforms

我已经读过你无法操纵不同线程中的控件。

我有两个使用相同Singleton类的控件。这两个控件在不同的线程中,这就是我使用单例在它们之间进行通信的原因。

我的问题是: 它只是Winforms的东西,不能跨线程操纵?我是否可以每次都通过Singleton传递数据,或者我是否必须以其他方式做到这一点?

编辑:

由于我得到的评论,我最好澄清一下,我不是在寻找怎么做,而是在我需要的时候,当我不这样做的时候。

2 个答案:

答案 0 :(得分:5)

Winforms控件只属于非线程安全的非常大的.NET Framework类集。像List<T>这样基本的东西不是线程安全的。在List的演员表中你可以做些什么,你可以使用lock关键字来确保只有一个线程可以同时访问成员。

但是这对Winforms控件不起作用,您不能在也访问该控件的操作系统代码中注入lock。因此,要求您的代码始终在创建控件的同一线程上运行。这是Application.Run()存在的原因,它是producer-consumer problem的通用解决方案。操作系统和其他进程中的多个线程产生并且您的单个UI线程消耗的地方,从而保持UI对象的线程安全。

技术上可以有多个UI线程,每个线程都有自己的顶级窗口(Form,而不是子控件)。然而,这也是一个非常危险的场景,SystemEvents.ThemeChanged事件是一个主要的麻烦制造者。工具箱中的大量控件订阅该事件,当活动Windows主题更改时,它们使用它来重绘自身。此事件在单个线程上引发,通常是您创建的第一个UI线程。

这意味着第二个线程上的控件将在错误的线程上获取此事件。哪个很容易造成死锁。工作站被锁定时很常见(Win + L键),切换到安全桌面并返回会触发ThemeChanged事件。调试过于丑陋,看起来like this,几乎无法修复。如果你这样做,那么你几乎被迫创建自己的控件类而不是使用工具箱。

&#34;不要这样做&#34;是唯一的好建议,永远不需要。

答案 1 :(得分:0)

如果您有要修改控件的线程,则应调用控件的BeginInvoke方法。例如:

Task.Run(() => 
{
    label1.BeginInvoke(new Action(() => 
    {
        label1.Text = "Something";
    }));
})