调度程序调用异步等待.net 4.6.1

时间:2019-04-25 17:57:39

标签: wpf async-await

我的目标是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);
}

我可以得到的在这些Wait之间实际更新UI的唯一方法是:

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

这是对的吗?这是便携式的吗?描述讨论在不同平台(UWP,Windows 10 Phone)上的不同方法。

可能会见Raymond Chen:https://devblogs.microsoft.com/oldnewthing/20190327-00/?p=102364

我明确不想使用“异步按钮事件”,因为我需要能够帮助用户,至少将逻辑放在十分之一秒的完成检查中,并且不要让用户猛烈抨击异步按钮处理程序以获取结果并使数据充满我的传感器网络。

您知道我最终也希望获得此结果,并以相同的事件处理程序代码进行处理,因此就像我不想使用BackroundWorker,然后让用户必须单击另一个按钮来轮询结果可能仍然是空的,使每个人都非常疯狂。而且我不想自动轮询结果,然后再次轮询传感器网络并导致更多拥塞。

2 个答案:

答案 0 :(得分:0)

  

我明确不想使用“异步按钮事件”,因为我需要能够帮助用户,至少将逻辑放在十分之一秒的完成检查中,并且不要让用户猛烈抨击异步按钮处理程序以获取结果并使数据充满我的传感器网络。

最简单的解决方案是按照其他所有人都解决的方式进行操作:在操作过程中禁用按钮。

async btnClick
{
  btn.Enabled = false;
  try
  {
    txtStatus.Text += "HOLD ON..";
    var result = await Task.Run(() => AsyncFunction());
    ... // update UI with result.
  }
  finally { btn.Enabled = true; }
}

答案 1 :(得分:0)

作为一个临时更新,我的测试表明异步事件处理程序和小的同步Waits都是合适的方法。通过仅将Wait(.1)委派给网络操作,启动DispatcherInvoke(()=> {txtStatus + =“ WAIT ..”}},然后紧随其后的是Dispatch(()=> {; / /},DispatcherPriority.ApplicationIdle)。

使用异步事件处理程序和网络调用中的IProgress(您甚至不需要Dispatcher,只需更改绑定控件)都会导致类似的进度更新,但初始响应可能是不可接受的。

使用同步等待会导致UI Paint停止运行,从而使任何逐渐更新的进度条显得非常生硬。

对我来说,进度条不是问题,因为我通过WAIT向操作员提供直接反馈。WAIT .. WAIT ..而进度条的所有工作都是通过拖延显示备份的方式。事实是,但我保留了足够的同步控制,以将振荡的警告卡在其中。振荡可能会变得急促,但是即使渐进式进度条停顿并开始,训练有素的操作员也会知道,如果CAUTION继续切换(无论多么不均匀),您就处于开启状态。

而且,我可以在同步代码中检测到这一点,然后立即对其进行处理,例如,卸载整个网络调用,然后强制用户排队和轮询。

更新

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上启动,甚至可能需要半秒钟才能看到发生了什么事情。

这几乎就像您希望冲刺队队长击中秒表还是与您一起跑步。如果尝试对两个10ms以下的网络执行ping操作,则延迟50毫秒甚至无法开始工作。但是,如果您那里甚至有一个异常的设备,它立即占用了整个100毫秒的等待时间,而STILL却不返回任何内容来报告进度,那么在屏幕上放置一些内容会很好。

对Cleary表示敬意,我在午餐后就切换到Reactive.NET。