Обновить метку пользовательского интерфейса при использовании Task.Factory.StartNew

#c# #wpf #multithreading #task-parallel-library

#c# #wpf #многопоточность #задача-параллельная-библиотека

Вопрос:

Я пытаюсь сделать свой пользовательский интерфейс более отзывчивым в моем приложении WPF. Я создаю новый поток, используя

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

В этом методе RecurseAndDeleteStart() я хочу обновить метку в пользовательском интерфейсе с удаляемым файлом.

Как это сделать?

Ответ №1:

Поскольку это WPF, вы можете использовать диспетчер и вызов Dispatcher.BeginInvoke , чтобы перенаправить обратный вызов в поток пользовательского интерфейса для обновления метки.

В качестве альтернативы вы можете передать TaskScheduler в свой метод и использовать его для обновления метки следующим образом:

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

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

Затем, внутри вашего метода, когда вы хотите обновить метку, вы могли бы сделать:

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

Это вернет вызов обратно в контекст синхронизации потока пользовательского интерфейса.

Комментарии:

1. Идеально! Именно то, что я искал.

2. 1 за то, что показал, что дочерняя задача может быть запущена в другом планировщике (и еще 1 за то, что показал мне CancellationToken.None — я проходил new CancellationToken() , но это показалось взломом!)

3. 1 Это решение простое, и мне не пришлось многое менять в моем проекте, чтобы реализовать его! Попробовал несколько других решений, но не смог реализовать их корректно.

Ответ №2:

Вы должны использовать label.Dispatcher.BeginInvoke(delegate) для вызова чего-либо из другого потока, что изменит содержимое метки.