Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fire events from different thread

Tags:

c#

wpf

In my main window (Thread A), I start a new thread (Thread B) which does some work while the user waits.

Thread B fires events if there is an error or extra information is required from the user, Thread A will listen to these events.

In Thread A's event listener I need to show dialog messages to the user, I have a custom dialog window and show it using dialogWindow.showDialog(). This works fine, but causes an error when I try and set the owner of the dialog, I do this dialogWindow.Owner = Window.GetWindow(this).

The error that I get is: The calling thread cannot access this object because a different thread owns it.

What is the correct way to listen for events that are fired from a different thread?

like image 750
Drahcir Avatar asked Dec 13 '22 03:12

Drahcir


2 Answers

The event listener code will run implicitly at the thread which fires the event, so the event listener is not thread-bound.

If you want to show something in the UI as a result of event handling, you should do the marshalling yourself. Something like that:

void OnEvent(object sender, EventArgs args)
{
    // runs in the event sender's thread
    string x = ComputeChanges(args);
    Dispatcher.BeginInvoke((Action)(
        () => UpdateUI(x)
    ));
}

void UpdateUI(string x)
{
    // runs in the UI thread
    control.Content = x;
    // - or -
    new DialogWindow() { Content = x, Owner = this }.ShowDialog();
    // - or whatever
}

So: you execute your computations (if any) preferrably in the background thread, without touching the UI; after that, when you know which are the needed changes in the UI, you execute the UI-updating code in the UI thread.

The Dispatcher is a property of a control, so if your code is a part of UI, you'll have your Dispatcher for free. Otherwise, you can take the dispatcher from any of the controls (e.g., control.Dispatcher).

like image 56
Vlad Avatar answered Dec 25 '22 02:12

Vlad


The correct way to raise an event to the UI thread from the background thread is that, the event should be raised on that Dispatcher, Key here is get the dispatcher of UIthread before hand.

UIDisaptcher.BeginInvoke((ThreadStart)(() => RaiseEventToUIThread()));

when the UI thread listens to the raised event it can set the Owner property(as the window was created by the UI thread).

like image 45
neo Avatar answered Dec 25 '22 03:12

neo