Продолжение задачи в streamе пользовательского интерфейса
Существует ли «стандартный» способ указать, что продолжение задачи должно выполняться в streamе, из которого была создана начальная задача?
В настоящее время у меня есть код ниже – он работает, но отслеживание диспетчера и создание второго действия кажется ненужным накладными расходами.
dispatcher = Dispatcher.CurrentDispatcher; Task task = Task.Factory.StartNew(() => { DoLongRunningWork(); }); Task UITask= task.ContinueWith(() => { dispatcher.Invoke(new Action(() => { this.TextBlock1.Text = "Complete"; } });
- Как использовать фоновый рабочий стол WPF
- Что делает InitializeComponent () и как он работает в WPF?
- Как перебрать строки инструментария WPF Datagrid
- WPF DataGrid - кнопка в столбце, получающая строку, из которой она появилась в обработчике событий Click
- Внедрить INotifyPropertyChanged в сгенерированные classы Entity Framework
- Цвет фона для Wpf
- Как сделать снимок экрана с помощью элемента управления WPF?
- как использовать MVVMLight SimpleIoc?
- Как связать с паролем в MVVM
- Почему привязка данных WPF к исключению ласточки?
- Связывание WPF ComboBox с пользовательским списком
- Почему WPF поддерживает привязку к свойствам объекта, но не полям?
- Как я могу получить DPI в WPF?
Вызовите продолжение с помощью TaskScheduler.FromCurrentSynchronizationContext()
:
Task UITask= task.ContinueWith(() => { this.TextBlock1.Text = "Complete"; }, TaskScheduler.FromCurrentSynchronizationContext());
Это подходит только в том случае, если текущий контекст выполнения находится в streamе пользовательского интерфейса.
С помощью async вы просто выполните:
await Task.Run(() => do some stuff); // continue doing stuff on the same context as before. // while it is the default it is nice to be explicit about it with: await Task.Run(() => do some stuff).ConfigureAwait(true);
Однако:
await Task.Run(() => do some stuff).ConfigureAwait(false); // continue doing stuff on the same thread as the task finished on.
Если у вас есть возвращаемое значение, которое необходимо отправить в пользовательский интерфейс, вы можете использовать общую версию следующим образом:
Это вызвано MVVM ViewModel в моем случае.
var updateManifest = Task.Run(() => { Thread.Sleep(5000); // prove it's really working! // GenerateManifest calls service and returns 'ShippingManifest' object return GenerateManifest(); }) .ContinueWith(manifest => { // MVVM property this.ShippingManifest = manifest.Result; // or if you are not using MVVM... // txtShippingManifest.Text = manifest.Result.ToString(); System.Diagnostics.Debug.WriteLine("UI manifest updated - " + DateTime.Now); }, TaskScheduler.FromCurrentSynchronizationContext());
Я просто хотел добавить эту версию, потому что это такой полезный stream, и я думаю, что это очень простая реализация. Я использовал это несколько раз в различных типах, если многопоточное приложение:
Task.Factory.StartNew(() => { DoLongRunningWork(); Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { txt.Text = "Complete"; })); });
J ust напишите свой код как ( Но использование ContinueWith
– хорошая практика, не беспокойтесь о ненужных накладных расходах для времени выполнения )
Task task = Task.Factory.StartNew(() => { DoLongRunningWork(); Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => { this.TextBlock1.Text = "Complete"; } });
Поместите код
Dispatcher
в блокfinally
если вы хотите убедиться, что это будет выполняться.
Попробуйте избежать TaskScheduler.FromCurrentSynchronizationContext()
поскольку от использования этого ваш stream пользовательского интерфейса может быть заблокирован вашим текущим streamом.