将线程安全访问方法写入Windows窗体控件的最短方法

在这篇文章中:

http://msdn.microsoft.com/en-us/library/ms171728(VS.80).aspx

作者使用以下方法对Windows窗体控件进行线程安全调用:

private void SetText(string text) { // InvokeRequired required compares the thread ID of the // calling thread to the thread ID of the creating thread. // If these threads are different, it returns true. if (this.textBox1.InvokeRequired) { SetTextCallback d = new SetTextCallback(SetText); this.Invoke(d, new object[] { text }); } else { this.textBox1.Text = text; } } 

是否有更短的方法来完成同样的事情?

C#3.0以及之后:

扩展方法通常是要走的路,因为您总是希望在ISynchronizeInvoke接口实现上执行操作,这是一个很好的设计选择。

您还可以利用匿名方法 (闭包)来解释您不知道要传递给扩展方法的参数的事实; 关闭将捕获所需的一切状态。

 // Extension method. static void SynchronizedInvoke(this ISynchronizeInvoke sync, Action action) { // If the invoke is not required, then invoke here and get out. if (!sync.InvokeRequired) { // Execute action. action(); // Get out. return; } // Marshal to the required context. sync.Invoke(action, new object[] { }); } 

然后你会这样称呼它:

 private void SetText(string text) { textBox1.SynchronizedInvoke(() => textBox1.Text = text); } 

这里,闭包在text参数上,该状态被捕获并作为传递给扩展方法的Action委托的一部分传递。

在C#3.0之前:

你没有lambda表达式的奢侈,但你仍然可以概括代码。 它几乎相同,但不是扩展方法:

 static void SynchronizedInvoke(ISynchronizeInvoke sync, Action action) { // If the invoke is not required, then invoke here and get out. if (!sync.InvokeRequired) { // Execute action. action(); // Get out. return; } // Marshal to the required context. sync.Invoke(action, new object[] { }); } 

然后用匿名方法语法调用它:

 private void SetText(string text) { SynchronizedInvoke(textBox1, delegate() { textBox1.Text = text; }); } 

1)使用匿名代表

 private void SetText(string text) { if (this.InvokeRequired) { Invoke(new MethodInvoker(delegate() { SetText(text); })); } else { this.textBox1.Text = text; } } 

2)AOP方法

 [RunInUIThread] private void SetText(string text) { this.textBox1.Text = text; } 

http://weblogs.asp.net/rosherove/archive/2007/05.aspx?PageIndex=2

3)使用lambda表达式(由其他人概述)。

编辑:我应该提到我不会认为这是一个最佳实践

如果您使用3.5,则可以使用扩展方法来实现以下效果:

 public static void SafeInvoke(this Control control, Action handler) { if (control.InvokeRequired) { control.Invoke(handler); } else { handler(); } } 

这基本上取自: 这里

然后使用它像:

 textBox1.SafeInvoke(() => .... ); 

当然修改你的用法的扩展等。

这对大多数人来说可能是显而易见的,但如果您需要检索值,您可以接受已接受的答案并添加另一种方法……

 public static T SynchronizedFunc(this ISynchronizeInvoke sync, Func func) { if (!sync.InvokeRequired) { // Execute the function return func(); } // Marshal onto the context return (T) sync.Invoke(func, new object[] { }); } 

我最近使用它以线程安全的方式处理表单…

 var handle = f.SynchronizedFunc(() => f.Handle); 

我找到的最短解决方案显示在下面的按钮示例中,其目标是更改按钮的文本。

  if (buttonX.InvokeRequired) buttonX.Invoke((Action)(() => buttonX.Text = "Record")); else buttonX.Text = "Record";