Reputation: 624
When I need to invoke some code in the specified thread, i am using something like this:
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
delegate void MethodToInvokeDelegate(string foo, int bar);
void MethodToInvoke(string foo, int bar)
{
DoSomeWork(foo);
DoMoreWork(bar);
}
void SomeMethod()
{
string S = "Some text";
int I = 1;
dispatcher.BeginInvoke(new MethodToInvokeDelegate(MethodToInvoke), new object[] {S, I});
}
This code works fine, but it's quite heavy. I'd like to make it without declaring MethodToInvoke
and MethodToInvokeDelegate
- using an anonymous method. But I can't figure out how to pass parameters to it.
I can't write this like:
dispatcher.BeginInvoke((Action)delegate() { DoSomeWork(S); DoMoreWork(I); });
I need to actually pass parameters to method.
Is it any way to write it short and simple?
Example:
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
int[] ArrayToFill = new int[3];
void SomeMethod()
{
for (int i = 0; i < 3; i++)
dispatcher.BeginInvoke( { ArrayToFill[i] = 10; } );
}
This code will not work: method will be called with i = 1, 2, 3 and will raise IndexOutOfRange exception. i
will be incremented before method begins to execute. So we need to rewrite it like:
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
int[] ArrayToFill = new int[3];
delegate void MethodToInvokeDelegate(int i);
void MethodToInvoke(int i)
{
ArrayToFill[i] = 10;
}
void SomeMethod()
{
for (int i = 0; i < 3; i++)
dispatcher.BeginInvoke(new MethodToInvokeDelegate(MethodToInvoke), new object[] {i});
}
Upvotes: 5
Views: 10490
Reputation: 201
yourUIcontrol.BeginInvoke(new MethodInvoker(delegate {
//your code goes here
}));
Upvotes: 1
Reputation: 35730
if you wish to avoid creating a delegate type for each call, make use of Action<>
, Action<,>
, etc
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
string S = "Some text";
int I = 1;
dispatcher.BeginInvoke(
(Action<string, int>)((foo, bar) =>
{
MessageBox.Show(bar.ToString(), foo);
//DoSomeWork(foo);
//DoMoreWork(bar);
}),
new object[] { S, I }
);
an example with ArrayToFill[j] = 10;
action can be fixed very simple:
for (int i = 0; i < 3; i++)
{
int j = i;
// lambda captures int variable
// use a new variable j for each lambda to avoid exceptions
dispatcher.BeginInvoke(new Action(() =>
{
ArrayToFill[j] = 10;
}));
}
Upvotes: 6
Reputation: 109822
Try this:
string S = "Some text";
int I = 1;
dispatcher.BeginInvoke(new Action(() =>
{
DoSomeWork(S);
DoMoreWork(I);
}));
[EDIT]
In response to your modified question:
The issue you are seeing there is modified closure problem.
To fix it, you merely need to copy the argument before invoking the method:
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
int[] ArrayToFill = new int[3];
for (int i = 0; i < 3; i++)
{
int index = i;
dispatcher.BeginInvoke(new Action(() => { ArrayToFill[index] = 10; } ));
}
Upvotes: 1