2011-12-14 118 views
0

我有一个主窗口窗体,并在该窗体中我有自定义控件,表示应用程序中的不同屏幕。我想访问此控件的子控件。有什么我没有得到这里...有时我得到这个错误:C#窗体窗体自定义控件跨线程操作

Cross-thread operation not valid: 
Control 'lblText' accessed from a thread 
other than the thread it was created on.

但有时一切正常。我不完全明白为什么错误...可能是与外部设备(MEI BillAcceptor)有一个事件(在Form1类内)做了更改控制...所以让我写一个简单的代码...

//user control 
public partial class Screen2 : UserControl 
{ 
    public void changeValue(string txt) 
    { 
     lblText.Text = txt; 
    } 
} 

和方法changeValue从当特定事件惜售一个Form1中称为...

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
     BillAcceptor.SomeBillAcceptorEvent += 
      new SomeBillAcceptorEventHandler(changeText); 
    } 

    private void changeText(object sender, EventArgs args) 
    { 
     _screen2.changeValue("some text"); 
    } 
} 

所以最讨厌的事情是,有时一切实际工作...所以我的问题是“我必须在这里使用Invoke吗?“或者我该如何解决这一方面,对应用变化较小...

回答

1

是的,如果有可能从另一个线程调用该方法,则需要使用Invoke。

您可以检查this.InvokeRequired(),如果属实,那么使用调用,如果假做一个正常通话。

0

出现这种情况是由于thread unsafe call

你应该只线程程序

检查this链接安全的调用。

3

在您的处理程序中。做这样的事情。

 if (this.InvokeRequired) 
     { 
      Invoke(new MethodInvoker(() => 
      { 
       _screen2.changeValue("some text"); 
      })); 
     } 
     else 
     { 
      _screen2.changeValue("some text"); 
     } 

我想这个事件是在一个独立的线程上提出的,而不是主UI线程。

0

简短的回答是肯定的,你必须使用Invoke。见this question and its accepted answer if you need details

究其原因,除了只抛出了一些时间,顺便说一句,可以归结为时机。你现在有一种竞争条件,有时候你很幸运,有时候你不幸。

顺便说一句,这是这种事情非常方便的模式。

  1. 重构任何将表单值设置为其私有的无效方法的代码。
  2. 在这种新方法中,请致电InvokeRequired。如果它返回true,则调用Invoke,传递当前方法以递归到它。如果它返回false,请继续并进行更改。
  3. 从事件处理程序调用此新方法。

例如:

private void ChangeScreen2() { 
    if (this.InvokeRequired) { 
     this.Invoke(new MethodInvoker(ChangeScreen2)); 
    } 
    else { 
     _screen2.changeValue("some text"); 
    } 
} 

private void changeText(object sender, EventArgs args) 
{ 
    ChangeScreen2(); 
} 

的想法是,你隔离修饰的形式进入这些方法总是与InvokeRequired检查开头的所有代码,并始终Invoke自己如果需要的话。此模式适用于.NET 1.0以上版本。为了更简洁的方法,请参阅this question的公认答案,它适用于.NET 3.0及更高版本。