2011-05-23 86 views
2

当我尝试访问WinForms控件时,出现错误Control accessed from a thread other than the thread it was created on。我知道所有的控件修改应该在UI线程中执行(需要BeginInvoke()等),但是我需要我的控件是只读的。WinForms线程安全控制访问

这里是我的简化代码:

string text = textBox.Text; 

什么是从另一个线程访问的WinForms控件的属性值的模式?

回答

0

必须使用BeginInvoke。如果需要返回值(例如,控件的文本内容),则可以使用EndInvoke等待完成。

这就是说,你可能想考虑用另一种方式做事;让GUI线程将数据推送到后台工作线程。这有助于减少与用户输入竞争的机会,并导致更清晰的GUI和核心逻辑分离的设计。

5

对于像这样微不足道的事情,您不必特意使用BeginInvoke,也可以使用Invoke,但是您需要在UI线程上调用该调用。您可以使用一些魔法来隐藏几个方法调用中令人讨厌的细节,然后使用扩展方法使其更清晰。例如,让我说我想扩展TextBox控件与一对夫妇获取和设置Text属性的方法。我可能会做这样的事情:

namespace System.Windows.Forms 
{ 
    public static class TextBoxExtensions 
    {   
     public static string GetTextThreadSafe(this TextBox box) 
     { 
      return GetTextBoxText(box); 
     } 

     public static void SetTextThreadSafe(this TextBox box, string str) 
     { 
      SetTextBoxText(box, str); 
     } 

     public static string GetTextBoxText(TextBox box) 
     { 
      if (box.InvokeRequired) 
      { 
       Func<TextBox, string> deleg = new Func<TextBox, string>(GetTextBoxText); 
       return box.Invoke(deleg, new object[] { box }).ToString(); 
      } 
      else 
      { 
       return box.Text; 
      } 
     } 

     public static void SetTextBoxText(TextBox box, string str) 
     { 
      if (box.InvokeRequired) 
      { 
       Action<TextBox, string> deleg = new Action<TextBox, string>(SetTextBoxText); 
       box.Invoke(deleg, new object[] { box, str }); 
      } 
      else 
      { 
       box.Text = str; 
      } 
     } 
    } 
} 

然后在另一个线程你可以调用文本框,如下所示:

Thread t = new Thread(new ThreadStart(() => 
{ 
    // Threadsafe call to set the text 
    SomeTextBox.SetTextThreadSafe("asdf"); 
    // Threadsafe call to get the text 
    MessageBox.Show(SomeTextBox.GetTextThreadSafe());     
})); 
t.IsBackground = true; 
t.Start();