How to change my StopButton.IsEnabled property value to "true" in a background worker in WPF and C#?

wpf

(afree) #1

I have a background worker that is used to preform some background work in my WPF application.

when the background worker is called, it tries to access a button.IsEnabled property to set it to "true" but it crushes and the debugger says that the thread can’t access UI elements.

The crush happens in these lines:

BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (x, y) => {
    
    stopButton.IsEnabled = true; // <-- the crush takes place here.
    
    // here the rest of my code, it's never reached in debuging mode.
};

How can i enable that stop button inside my background worker? thanks


(this.is.sparta) #2

You can’t access UI elements from a Background thread.

you will need to invoke your UI elements functions and property changes using a dispatcher in WPF; something like this:

BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (x, y) => {
    
    stopButton.Dispatcher.BeginInvoke(new Action(() => {
        stopButton.IsEnabled = true;
    }));
    
    // the rest of your code goes here...
};

Notice there are two ways to do that either using Dispatcher.BeginInvoke or Dispatcher.Invoke, the difference is this:

  • Dispatcher.BeginInvoke:
    used to Call the given action or function without blocking the calling thread, meaning in our case the thread will go forward and execute the rest of your code and at the same time the UI thread will be handling the UI update for us in parallel.

  • Dispatcher.Invoke:
    This will block the calling thread until the UI thread has done executing the given action or function. you can say it’s like regular function calling instruction but it’s just executed on the other thread’s context.


(Yassine) #3

Since you are changing a UI related property (aka a property that affects the UI directly) in your case stopButton.IsEnabled Then I believe it will make sense and be more user friendly if you use Dispatcher.BeginInvoke.

Dispatcher.BeginInvoke: Executes your action asynchronously, and it’s less prioritized which means it wont freeze the entire Application just to Enable/Disable a button and that’s best for performance. And it wont freeze your BackgroundWorker as well…

bw.DoWork += (x, y) => {
   App.Dispatcher.BeginInvoke(new Action(() => { stopButton.IsEnabled = true; }));
};

That’s it.