C# 为windows窗体控件编写线程安全访问方法的最短方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/571706/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Shortest way to write a thread-safe access method to a windows forms control
提问by Justin Tanner
In this article:
在本文中:
http://msdn.microsoft.com/en-us/library/ms171728(VS.80).aspx
http://msdn.microsoft.com/en-us/library/ms171728(VS.80).aspx
The author uses the following method to make thread-safe calls to a Windows Forms control:
作者使用以下方法对 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;
}
}
Is there a shorter way to accomplish the same thing?
有没有更短的方法来完成同样的事情?
采纳答案by casperOne
C# 3.0 and after:
C# 3.0 及之后:
An extension method would generally be the way to go, since you're always going to want to perform an action on an ISynchronizeInvoke
interfaceimplementation, it's a good design choice.
扩展方法通常是可行的方法,因为您总是希望对ISynchronizeInvoke
接口实现执行操作,这是一个很好的设计选择。
You can also take advantage of anonymous methods(closures) to account for the fact that you don't know what parameters to pass to the extension method; the closure will capture the state of everything needed.
您还可以利用匿名方法(闭包)来解决您不知道将哪些参数传递给扩展方法的事实;关闭将捕获所需的一切状态。
// 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[] { });
}
You'd then call it like this:
然后你会这样称呼它:
private void SetText(string text)
{
textBox1.SynchronizedInvoke(() => textBox1.Text = text);
}
Here, the closure is over the text
parameter, that state is captured and passed as part of the Action
delegatepassed to the extension method.
在这里,闭包在text
参数上,该状态被捕获并作为传递给扩展方法的Action
委托的一部分传递。
Before C# 3.0:
在 C# 3.0 之前:
You don't have the luxury of lambda expressions, but you can still generalize the code. It's pretty much the same, but not an extension method:
您没有 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[] { });
}
And then you call it with anonymous method syntax:
然后你用匿名方法语法调用它:
private void SetText(string text)
{
SynchronizedInvoke(textBox1, delegate() { textBox1.Text = text; });
}
回答by Quintin Robinson
Edit: I should mention I would not consider this to be a Best Practice
编辑:我应该提到我不会认为这是最佳实践
If you are using 3.5 you can make an extension method to the effect of:
如果您使用的是 3.5,您可以创建一个扩展方法,以达到以下效果:
public static void SafeInvoke(this Control control, Action handler) {
if (control.InvokeRequired) {
control.Invoke(handler);
}
else {
handler();
}
}
this is basically taken from: Here
这基本上取自:这里
Then use it like:
然后像这样使用它:
textBox1.SafeInvoke(() => .... );
Of course modify the extension etc for your usages.
当然,根据您的用途修改扩展名等。
回答by alex2k8
1) Using anonymous delegate
1) 使用匿名委托
private void SetText(string text)
{
if (this.InvokeRequired)
{
Invoke(new MethodInvoker(delegate() {
SetText(text);
}));
}
else
{
this.textBox1.Text = text;
}
}
2) AOP approach
2)AOP方式
[RunInUIThread]
private void SetText(string text)
{
this.textBox1.Text = text;
}
http://weblogs.asp.net/rosherove/archive/2007/05.aspx?PageIndex=2
http://weblogs.asp.net/rosherove/archive/2007/05.aspx?PageIndex=2
3) Using lambda expressions (outlined by others).
3) 使用 lambda 表达式(由其他人概述)。
回答by Paul Hatcher
This may be obvious to most, but you can take the accepted answer and add another method if you need to retrieve the value...
这对大多数人来说可能是显而易见的,但是如果您需要检索值,您可以采用已接受的答案并添加另一种方法......
public static T SynchronizedFunc<T>(this ISynchronizeInvoke sync, Func<T> func)
{
if (!sync.InvokeRequired)
{
// Execute the function
return func();
}
// Marshal onto the context
return (T) sync.Invoke(func, new object[] { });
}
I used this recently to get handle of the form in a thread-safe way...
我最近用它来以线程安全的方式处理表单......
var handle = f.SynchronizedFunc(() => f.Handle);
回答by Spydee
The shortest solution I have found is shown in the button example below where the goal is to change the text of a button.
我找到的最短解决方案显示在下面的按钮示例中,其目标是更改按钮的文本。
if (buttonX.InvokeRequired)
buttonX.Invoke((Action)(() => buttonX.Text = "Record"));
else
buttonX.Text = "Record";