диспетчер вызывает асинхронное ожидание .net 4.6.1 - PullRequest
0 голосов
/ 25 апреля 2019

Я нацеливаюсь на WPF .NET 4.6.1. Я постоянно этим занимаюсь:

btnClick
{
Task T1 = Task.Run<List<Double>>( AsyncFunction );
T1.Wait(.1);
Dispatcher.Invoke(() => { txtStatus.Text+="HOLD ON.."; };
T1.Wait(.1);
}

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

Dispatcher.Invoke(new Action(()=>{}),priority: DispatcherPriority.ApplicationIdle);

Это правильно? Это портативный? Опишите обсуждение различных подходов на разных платформах (UWP, Windows 10 Phone).

Возможно, увидеть Рэймонда Чена: https://devblogs.microsoft.com/oldnewthing/20190327-00/?p=102364

Я не хочу использовать Async Button Event, потому что мне нужно иметь возможность помочь пользователю, по крайней мере, поставить логику для проверки выполнения одной десятой секунды, и чтобы пользователь не отбрасывал обработчик асинхронной кнопки, пытаясь получить результаты и переполнение моей сенсорной сети данными.

Вы знаете, что в конечном итоге я тоже хочу получить результат и обработать его в одном и том же коде обработчика событий, поэтому я не хочу использовать BackroundWorker, а затем пользователь должен нажать другую кнопку, чтобы опросить Результаты, которые могут остаться пустыми и сделать всех действительно очень сумасшедшими. И я не хочу автоматически опрашивать результаты, а затем снова опрашивать сеть датчиков и вызывать БОЛЬШЕ перегрузки.

Ответы [ 2 ]

0 голосов
/ 26 апреля 2019

Как временное обновление, мое тестирование показывает, что оба асинхронных обработчика событий и небольшие синхронные ожидания являются подходящими подходами. Я достигаю значительно лучшего начального ответа, делегировав только сетевую операцию Wait (.1), инициировав DispatcherInvoke (() => {txtStatus + = "WAIT .."}, а затем сразу следует Dispatch (() => {; / /}, DispatcherPriority.ApplicationIdle).

Использование асинхронного обработчика событий и IProgress (вам даже не нужен Dispatcher, просто измените связанный элемент управления) внутри сетевого вызова приводит к аналогичному обновлению прогресса, но с первоначальным ответом, который может быть неприемлемым.

Использование синхронного ожидания приводит к остановке рисования пользовательского интерфейса, из-за чего любой постепенно обновляемый индикатор выполнения выглядит очень резко.

Для меня, индикатор выполнения - это не проблема, потому что я даю оператору прямую обратную связь с WAIT .. WAIT .. WAIT .. И все, что делает индикатор выполнения, показывает, останавливаясь, насколько резервное копирование дело в том, но я сохраняю достаточно синхронного контроля, чтобы затормозить колеблющуюся осторожность. Колебание может быть прерывистым, но обученные операторы будут знать, если это предупреждение будет продолжаться, хотя неравномерно, вы включены, даже если постепенный индикатор выполнения останавливается и запускается.

И я могу обнаружить это в синхронном коде, а затем что-то сделать на лету, например, разгрузить весь сетевой вызов и затем заставить пользователя поставить в очередь и опросить.

UPDATE

async Task<List<Double>> NetworkList(IProgress<Int32> NetworkProgress)
{
List<Double> _results = new List<Double>();
foreach(var aNetwork in LotsOfNetworksCouldTakeAwhile)
{
SendPingFarAwayLand();
await Task.Delay(delay: TimeSpan.Frommilliseconds(100);
Double PingTime = GetPingTimeOrNull();
_results.Add(PingTIme);
NetworkProgress.Report( aNetwork.NetworkID );
}
}


async btnClick
{
TimeSpan IDLE_LONG_ENOUGH_SO_DISPATCHER_UPDATES_UI = TimeSpan.FromMilliseconds(50);
txtStatus += "WORKING...";
await Task.Delay(delay: IDLE_LONG_ENOUGH_SO_DISPATCHER_UPDATES_UI);
Task<List<Double>> results = await NetworkList(_Progress);
dependencyObject1.ObservableList1.Add(results);
return;
}

Кажется, это работает по крайней мере на моем компьютере. Достаточно около 50 миллисекунд, чтобы гарантировать, что диспетчер немедленно обработает ваше последнее сообщение «РАБОТАЕТ ...». Если вы этого не сделаете, вы можете нажать диспетчер в цикле повышения, но, возможно, нет, и он запустится в LongNetworkList, и может пройти полсекунды, прежде чем вы даже увидите, что что-то происходит.

Это похоже на то, хотите ли вы, чтобы капитан команды спринта поразил секундомер или побежал с вами. Задержка в 50 миллисекунд даже для начала работы кажется большой, если вы пытаетесь пропинговать две сети на 10 мс. Но если у вас есть хотя бы один аберрант, который сразу же забирает все ожидаемые 100 мс, и STILL ничего не возвращает, чтобы вы могли сообщить о достигнутом прогрессе, было бы неплохо вывести что-нибудь на экран.

Слава Клири, я перехожу на Reactive.NET сразу после обеда.

0 голосов
/ 25 апреля 2019

Я не хочу использовать Async Button Event, потому что мне нужно иметь возможность помочь пользователю, по крайней мере, поставить логику для проверки завершения одной десятой секунды, и чтобы пользователь не хлопал обработчиком асинхронной кнопки, пытаясь получить результаты и переполнение моей сенсорной сети данными.

Самое простое решение - сделать это так, как это решают все остальные: отключить кнопку во время выполнения операции.

async btnClick
{
  btn.Enabled = false;
  try
  {
    txtStatus.Text += "HOLD ON..";
    var result = await Task.Run(() => AsyncFunction());
    ... // update UI with result.
  }
  finally { btn.Enabled = true; }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...