为什么我不能从另一个线程访问UI控件的属性?

时间:2014-11-11 12:58:43

标签: c# multithreading user-interface

我读过它不可能从另一个线程(不仅是GUI,而是所有2个不同的线程)访问UI元素,并看到一个代码如何解决它,但没有找到解释为什么可以& #39;我这样做?

2 个答案:

答案 0 :(得分:0)

MSDN给出不允许这样做的原因:

  

对Windows窗体控件的访问本质上不是线程安全的。如果您有两个或多个线程来操纵控件的状态,可以强制控件进入不一致状态。其他与线程相关的错误也是可能的,包括竞争条件和死锁。确保以线程安全的方式访问您的控件非常重要。

从技术上讲,我有可能(也许他们可以将它留在设计中),但问题是微软的底层代码不是线程安全的。这可能与Windows的内部工作原理有关,并且它们在Win32 UI模型中缺乏线程安全性。

答案 1 :(得分:-1)

除了GUI线程(主线程)之外,您无法从任何其他线程更改GUI。也就是说你可以从任何线程中读取控件(文本框等)中的数据而没有问题,如果你想从另一个线程更改控件,你需要使用这样的东西:

textBox1.Invoke((MethodInvoker)(() =>
{
    textBox1.Text = "text changed from another thread";
}));

这样做的缺点是,现在您调用此主题的线程将被阻止,直到对文本框的更改完成为止。如果你不经常从你的线程更新你的控件,这不是一个问题,但如果你想经常这样做,你需要创建一个第三个线程来处理更新,具体取决于工作线程正在做什么。像这样的东西

List<string> list = new List<string>();
Thread workThread = new Thread(dowork =>
{
    //random work
    for(int a = 0; a< 1000000;a++)
    {
        list.Add(a+" iteration");
        Thread.Sleep(10);
    }
});
workThread .Start();
bool updateThreadWorking = true;
Thread updateThread = new Thread(dowork =>
{
    while(updateThreadWorking)
    {
        while(list.Count > 0)
        {
            listBox.Invoke((MethodInvoker)(() =>
                listBox.Items.Add(list[0]);
            }));
            list.RemoveAt(0);
        }
        Thread.Sleep(200);
    }
});
updateThread .Start();

现在,workthread正在全速运行而不会被UI阻止,并且UI仍然会在当前状态下更新