In this article:
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:
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?
Gets a value indicating whether the caller must call an invoke method when making method calls to the control because the caller is on a different thread than the one the control was created on. public: property bool InvokeRequired { bool get(); }; C# Copy.
If it's critical that you read the correct values each time, then you'll need to make the property thread-safe. In this article, I'll show two ways to make this property thread-safe: by using a lock and by using the Interlocked class.
C# 3.0 and after:
An extension method would generally be the way to go, since you're always going to want to perform an action on an ISynchronizeInvoke
interface implementation, it's a good design choice.
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
delegate passed to the extension method.
Before 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:
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; }); }
1) Using anonymous delegate
private void SetText(string text)
{
if (this.InvokeRequired)
{
Invoke(new MethodInvoker(delegate() {
SetText(text);
}));
}
else
{
this.textBox1.Text = text;
}
}
2) AOP approach
[RunInUIThread]
private void SetText(string text)
{
this.textBox1.Text = text;
}
http://weblogs.asp.net/rosherove/archive/2007/05.aspx?PageIndex=2
3) Using lambda expressions (outlined by others).
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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With