Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task ContinueWith() Not Updating Cursor on UI Thread

Tags:

c#

task

I'm working on a WPF app and I simply want to alter the cursor before and after the task runs. I have this code:

this.Cursor = Cursors.Wait;

Task.Factory.StartNew(() => PerformMigration(legacyTrackerIds)).ContinueWith(_ => this.Cursor = Cursors.Arrow);

The cursor indeed changes to the wait cursor, but it doesn't change back to the arrow when the task is done. If I put a breakpoint in the ContinueWith() method, it gets hit. But the cursor doesn't change back to an arrow. Why?

This was the old way I was trying it. The cursor changed back to an arrow, but I don't want to Wait() for the task.

this.Cursor = Cursors.Wait;

Task.Factory.StartNew(() => PerformMigration(legacyTrackerIds)).Wait();

this.Cursor = Cursors.Arrow;
like image 429
Bob Horn Avatar asked Aug 31 '12 14:08

Bob Horn


3 Answers

The cursor change needs to be done on the UI thread. You can either use the the overload of ContinueWith that takes a task scheduler:

var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 

Task.Factory
  .StartNew(() => PerformMigration(legacyTrackerIds))
  .ContinueWith(_ => this.Cursor = Cursors.Arrow, uiScheduler);

Or use the Dispatcher.Invoke method:

Task.Factory
  .StartNew(() => PerformMigration(legacyTrackerIds))
  .ContinueWith(_ => { Dispatcher.Invoke(() => { this.Cursor = Cursors.Arrow; }); });
like image 135
Rich O'Kelly Avatar answered Oct 20 '22 14:10

Rich O'Kelly


I think you need to use the correct synchronization context:

this.Cursor = Cursors.Wait; 

var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext()); 

Task.Factory.StartNew(() => PerformMigration(legacyTrackerIds))
            .ContinueWith(_ => this.Cursor = Cursors.Arrow, uiScheduler);
like image 35
Daniel Hilgarth Avatar answered Oct 20 '22 14:10

Daniel Hilgarth


The problem is that the continuation needs to run in the UI thread. Currently it's being done in a background thread.

Add TaskScheduler.FromCurrentSynchronizationContext() to the second parameter of ContinueWith to have it run in the UI thread.

like image 44
Servy Avatar answered Oct 20 '22 13:10

Servy