I have a .Net 4.0 class that has a custom event handler (StatusChanged
). I am trying to consume this class via a thread. I don't have the luxury of using BackgroundWorker
because libraries I use do not support multi thread apartment state.
One of the parameters in the StatusChanged
delegate is a string.
In the UI, a button click initializes a thread that uses my class.
I am trying to make it so a UI control (WPF) gets updated to be the StatusChanged
string parameter when StatusChanged
event fires. My understanding is that Dispatcher.Invoke
can do this, but I am not having any luck figuring out how to pull the string out of it.
Essentially, I am trying to get the equivalent of BackgroundWorker.ProgressChanged
(with the ProgressChangedEventArgument.UserState
).
Here is some scaled-down code to demonstrate what I'm getting at:
Class with event handler:
public class MyClass
{
public event EventHandler StatusChanged;
private void alertStatus(string message)
{
if(StatusChanged == null)
return;
this.StatusChanged(message, new EventArgs());
}
public void DoStuff()
{
///Do Stuff 1
alertStatus("Done with stuff #1");
///Do Stuff 2
alertStatus("Done with stuff #2");
}
}
So a button's .Click event would do something like this:
private void buttonClicked(object sender, EventArgs e)
{
Thread t = new Thread(doWork);
t.Start();
}
private void doWork()
{
MyClass class = new MyClass();
class.StatusChanged += ...
class.DoStuff();
///As StatusChanged fires within MyClass, a UI Textbox would get updated
}
It's easiest just to use a lambda expression:
private void doWork()
{
// Name changed to avoid it being a keyword
MyClass clazz = new MyClass();
clazz.StatusChanged += (sender, args) => {
string message = (string) sender; // This is odd
Action action = () => textBox.Text = message;
Dispatcher.Invoke(action);
};
clazz.DoStuff();
}
It's very odd using a string as the sender of an event though - it would be better to use a subclass of EventArgs
, and make that store the message - then make your event use EventHandler<T>
instead of just EventHandler
.
The above code is slightly confusing because you're subscribing to the event with one delegate, then passing another to Dispatcher.Invoke
- hence the two lambda expressions (one inside another). You could always use a method group instead, at least for the outer one:
private void doWork()
{
// Name changed to avoid it being a keyword
MyClass clazz = new MyClass();
clazz.StatusChanged += HandleStatusChange;
clazz.DoStuff();
}
private void HandleStatusChange(object sender, EventArgs e)
{
string message = (string) sender; // This is odd
Action action = () => textBox.Text = message;
Dispatcher.Invoke(action);
}
See more on this question at Stackoverflow