其他对象引发的工作事件时的跨线程操作

时间:2012-07-07 10:17:42

标签: c# visual-studio-2010 thread-safety multithreading

我有一个类'userdetails',它有一个名为'detailschanged'的事件。每当用户细节发生变化时,它都会被引发 当我在新表单中创建'userdetails'(objUserDetails)的新对象时,我将订阅事件'detailschanged'以指示用户有关datachange的信息。

objUserDetails.detailschanged += InformtoUser

InformtoUser是一种新形式的方法。在InformtoUser方法中,我正在访问表单的控件(比如标签的文本属性) 访问控件时,我收到“交叉线程操作”错误 如何避免这种交叉线程操作?

2 个答案:

答案 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 = ""));