#c# #wpf #task #invoke #dispatcher
#c# #wpf #задача #вызвать #диспетчер
Вопрос:
У меня есть приложение WPF для мониторинга данных, и я пишу Task.Run
в загруженном методе для выполнения работы и отображения данных в графическом интерфейсе.
Код выглядит следующим образом:
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
await Task.Run(() => DoAddAsync());
}
void DoAddAsync()
{
while (true)
{
this.Dispatcher.Invoke(() =>
{
//Do Some
});
}
}
Это работает нормально, и я могу изменить компонент в графическом интерфейсе пользователя без зависания.
Но если я выполняю метод в this.Dispatcher.Invoke
, графический интерфейс зависает, и я ничего не могу сделать, пока этот метод не закроется.
Кто-нибудь может помочь мне запустить метод в this.Dispatcher.Invoke
без зависания GUI?
Комментарии:
1.
while (true)
с помощью onlyDispatcher.Invoke
бессмысленно, поскольку весь ваш код все еще выполняется в потоке пользовательского интерфейса. Выполняйте фактические асинхронные действия снаружиInvoke
и обновляйте элементы пользовательского интерфейса только с помощьюInvoke
.2. Или, что еще лучше, используйте
IProgress<T>
вместоDispatcher.Invoke
.
Ответ №1:
Вы можете использовать асинхронный цикл. Хотя это и выглядит как бесконечный цикл, на самом деле это не так. Из-за ожидания задачи задержки этот метод периодически возвращает управление вызывающей его стороне. Если бы это не был асинхронный метод с допустимой асинхронной операцией, это был бы синхронный метод и привел бы к тупиковой ситуации в пользовательском интерфейсе при его вызове.
Но поскольку это не так, оно работает по мере необходимости и дает вам как очень четкое представление о том, что должен делать код, так и удерживает нас в потоке пользовательского интерфейса все время (магия await!), поэтому у нас нет проблем с многопоточностью или несколькими делегатами / обратными вызовами.
private async Task DoAddAsync()
{
while (true)
{
// do the work in the loop
// ....
// don't run again for at least 200 milliseconds
await Task.Delay(200);
}
}
Однако реальная хитрость в том, чтобы заставить это работать, заключается не в методе DoAddAsync. Так мы это называем. Вы не ожидаете вызова к ней.
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
DoAddAsync()
}
Вы также можете обновить свой способ, но это приводит к появлению нескольких делегатов, потенциальным сложностям многопоточности в зависимости от выполняемой работы, и нам все еще нужно вернуться к потоку пользовательского интерфейса, чтобы обновить пользовательский интерфейс.
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
await Task.Run(async () =>
{
while (true)
{
// do the work in the loop
// update the UI on the UI thread
Dispatcher.Invoke(() => // do some );
// don't run again for at least 200 milliseconds
await Task.Delay(200);
}
});
}
Комментарии:
1. Ваше предложение работает нормально. но моя проблема заключается в вызове метода в цикле while. Можете сказать мне, как определить метод, который я могу вызывать в цикле while без зависания. это моя настоящая проблема
2. вы пытались добавить
await Task.Delay(200);
?