我有一个类'userdetails',它有一个名为'detailschanged'的事件。每当用户细节发生变化时,它都会被引发 当我在新表单中创建'userdetails'(objUserDetails)的新对象时,我将订阅事件'detailschanged'以指示用户有关datachange的信息。
objUserDetails.detailschanged += InformtoUser
InformtoUser是一种新形式的方法。在InformtoUser方法中,我正在访问表单的控件(比如标签的文本属性) 访问控件时,我收到“交叉线程操作”错误 如何避免这种交叉线程操作?
答案 0 :(得分:3)
这里的问题是线程安全:
对Windows窗体控件的访问本质上不是线程安全的。如果有两个或多个线程操纵控件的状态,则可以强制控件进入不一致状态。其他与线程相关的错误也是可能的,例如竞争条件和死锁。确保以线程安全的方式访问控件非常重要。
在不使用Invoke方法的情况下,从创建控件的线程以外的线程调用控件是不安全的。
在对Windows窗体控件进行任何跨线程调用时,您需要使用Control.Invoke
。
例如:
delegate void SetTextCallback(string text);
private void SetText(string text)
{
if (textBox.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
textBox.Text = text;
}
}
或:
this.Invoke((MethodInvoker) delegate {
this.textBox.Text = "Some text here";
});
有关详细信息,请参阅 How to: Make Thread-Safe Calls to Windows Forms Controls 。
答案 1 :(得分:1)
UI控件只能从UI线程更新。 如果你正在使用WinForms,你应该这样做:
mycontrol.Invoke((MethodInvoker)(() =>
{
mycontrol.Text="some text";
}));
如果你在WPF,那么你应该使用调度员:
myControl.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => myControl.Text = ""));