为什么可以';t我从另一个线程访问UI控件的属性
本文关键字:访问 线程 另一个 UI 控件 属性 为什么 | 更新日期: 2023-09-27 18:30:08
我读到不可能从另一个线程(不仅是GUI,还有所有2个不同的线程)访问UI元素,并看到了如何解决它的代码,但没有找到解释为什么我不能这样做?
MSDN给出的不允许这样做的原因:
对Windows窗体控件的访问本质上不是线程安全的。如果有两个或多个线程在处理控件的状态,则可能会强制控件进入不一致的状态。其他与线程相关的错误也是可能的,包括争用条件和死锁。重要的是要确保以线程安全的方式访问控件。
所以从技术上讲,我是可能的(也许他们故意忽略了它),但问题是微软的底层代码不是线程安全的。这可能与Windows的内部工作以及Win32 UI模型中缺乏线程安全性有关。
除了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();
现在,工作线程正在全速工作,而不会被UI阻塞,并且UI仍在更新当前状态