To invoke a method via a delegate, the delegate must have the same signature as the method. The example in the first post invokes a method that has no parameters and no return value. In that case you can use the existing MethodInvoker delegate. If you need to specify one or more parameters or get a return value though, you will have to declare your own delegate type.
Let's say that you want to set the Text property of a TextBox from a worker thread. From the first post we know the first step is to declare a method that does what we want:
CSharp Code:
private void SetTextBoxText(string text)
{
this.textBox1.Text = text;
}
Now, that method has a parameter so we cannot use the MethodInvoker delegate. We must declare our own delegate type with the same signature. The signature is basically the parameter list and the return type. To create your delegate declaration you should copy the method declaration:
CSharp Code:
private void SetTextBoxText(string text);
then add the 'delegate' key word:
CSharp Code:
private delegate void SetTextBoxText(string text);
and finally change the name:
CSharp Code:
private delegate void SetTextBoxTextInvoker(string text);
Now that we have declared our new delegate type we can create instances of it just as we did with the MethodInvoker.
The next step from above was to add a test for the InvokeRequired property of our control:
CSharp Code:
private void SetTextBoxText(string text)
{
if (this.textBox1.InvokeRequired)
{
}
else
{
this.textBox1.Text = text;
}
}
Finally we call the control's Invoke method and pass our delegate:
CSharp Code:
private void SetTextBoxText(string text)
{
if (this.textBox1.InvokeRequired)
{
this.
textBox1.
Invoke(new SetTextBoxTextInvoker
(SetTextBoxText
),
text);
}
else
{
this.textBox1.Text = text;
}
}
Notice that, while last time the only parameter passed to the Invoke method was the delegate, this time we pass the 'text' value as well. Any parameters passed to Invoke after the delegate will then be passed again to the method that gets invoked by the delegate. Our delegate will be invoking the SetTextBoxText method, which requires a 'text' parameter. That code gets the 'text' value passed in to the first call and propagates it to the second call via the Invoke method and the delegate.
The above example passes a single parameter but the very same mechanism can be used to pass multiple parameters. Here's a similar example that can be used to set the Text property of any control:
CSharp Code:
private delegate void SetControlTextInvoker(Control ctl, string text);
private void SetControlText(Control ctl, string text)
{
if (ctl.InvokeRequired)
{
ctl.
Invoke(new SetControlTextInvoker
(SetControlText
),
ctl,
text);
}
else
{
ctl.Text = text;
}
}
Pass in the control and the text and the method handles the rest. It tests the InvokeRequired property and calls the Invoke method of the appropriate control, then sets the Text property of that same control.
EDIT: A note for those using .NET 1.x. The Control.Invoke method signature changed in .NET 2.0 to accept any number of individual parameters. Previous versions required any parameters to be passed within an array. That means that while this is fine in .NET 2.0 and above:
CSharp Code:
ctl.
Invoke(new SetControlTextInvoker
(SetControlText
),
ctl,
text);
you would have to do this in .NET 1.x:
vb.net Code:
ctl.Invoke(new SetControlTextInvoker(SetControlText),
new object[] {ctl,
text});