19

I am trying to make my UI more responsive in my WPF app. I spawn a new thread using

Task.Factory.StartNew( () => RecurseAndDeleteStart() );

In that method RecurseAndDeleteStart() I want to update a label in the UI with the file that is being deleted.

How does one accomplish this?

Demetri
  • 598
  • 2
  • 4
  • 14

2 Answers2

46

Since it's WPF, you can use the Dispatcher and call Dispatcher.BeginInvoke to marshal the call back to the UI thread to update the label.

Alternatively, you can pass a TaskScheduler into your method, and use it to update the label as follows:

// This line needs to happen on the UI thread...
TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();

Task.Factory.StartNew( () => RecurseAndDeleteStart(uiScheduler) );

Then, inside your method, when you want to update a label, you could do:

Task.Factory.StartNew( () => 
  {
      theLabel.Text = "Foo";
  }, CancellationToken.None, TaskCreationOptions.None, uiScheduler);

This will push the call back onto the UI thread's synchronization context.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • 1
    Perfect! Exactly what I was looking for. – Demetri May 20 '11 at 18:36
  • 1
    +1 for showing that a child task can be run on a different scheduler (and another +1 for showing me `CancellationToken.None` - I've been passing `new CancellationToken()` but it seemed a hack!) – axeman Aug 19 '13 at 20:15
  • +1 This solution is simple, and I didn't have to change to much in my project to implement it! Tried a few other solutions but couldn't implement them correcly. – Fredrik Andersson Oct 12 '16 at 19:34
2

You have to use the label.Dispatcher.BeginInvoke(delegate) to invoke anything from a different thread that will change the contents of the label.

Liam
  • 27,717
  • 28
  • 128
  • 190
Andrew
  • 2,530
  • 16
  • 9