我正在为程序的特定部分编写功能,这要求我不断更改窗口上多个标签的文本,直到用户按下按钮。我已经创建了一个线程来实现这一点,并很快注意到运行时抱怨标签的跨线程访问,并给出错误消息:
跨线程操作无效:控制' label2'从创建它的线程以外的线程访问。
我自从了解到不允许访问UI线程以外的线程中的System.Windows.Forms.Control
成员。但是,我的问题与以下简化代码有关:
private void myThread(){
//'labels' is an array of all labels on my form
Label currLabel = labels[rand.Next(0, labels.Length)];
currLabel.BackColor = Color.Yellow; //This works with no complaint from the runtime
currLabel.Text = "Hello"; //This causes the previously-mentioned error
}
那么,为什么我能够在UI线程以外的线程中更改标签的某些属性,但其他的只是禁止?我在这里错过了一些更大的概念吗?任何帮助表示赞赏。
答案 0 :(得分:1)
只能在主UI线程上访问UI组件。因此,正如多线程行为一样,在系统上创建一个新线程。通过这样做,主UI的线程不会被阻止。话虽这么说,如果你想访问控件,你需要调用Invoke
或BeginInvoke
方法,具体取决于条件
样品:
Label1.BeginInvoke((Action) (() => { \\Multiple Line of codes here. }));
另外,请检查以下链接:
Accessing UI Control from BackgroundWorker Thread
Solve a cross-threading Exception in WinForms
添加注意:虽然在某些时候可能不使用Invoke
方法,但它仍然比抱歉更安全。有些人最终可能会在运行时抛出此类异常取决于程序运行的情况
对Windows窗体控件的访问本质上不是线程安全的。如果有两个或多个线程操纵控件的状态,则可以强制控件进入不一致状态。其他与线程相关的错误也是可能的,例如竞争条件和死锁。确保以线程安全的方式访问控件非常重要。
答案 1 :(得分:1)
那么,为什么我能够在UI线程以外的线程中更改标签的某些属性,但其他线程只是禁止?
可能性包括:
由于2%和3在99%的时间内无法区分,因此当你处于情境3时,你可能会认为你处于情境2中。这意味着你无法重现的随机崩溃。