我的目标是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然后让用户必须单击另一个按钮来轮询结果,可能仍然空虚,让每个人真的很难受。我不想自动轮询结果,然后再次轮询传感器网络并导致更多拥塞。
我明确不想使用异步按钮事件,因为我需要能够帮助用户,至少把逻辑进行十分之一秒的完成检查,而不是让用户砰地关上异步按钮处理程序试图获得结果和拥塞我传感器网络与数据。
最简单的解决方案是按照其他人解决的方式进行:在操作过程中禁用按钮。
async btnClick
{
btn.Enabled = false;
try
{
txtStatus.Text += "HOLD ON..";
var result = await Task.Run(() => AsyncFunction());
... // update UI with result.
}
finally { btn.Enabled = true; }
}
作为临时更新,我的测试表明异步事件处理程序和小型同步Wait都是合适的方法。我通过仅将Wait(.1)委托给网络操作,启动DispatcherInvoke(()=> {txtStatus + =“WAIT ..”}并紧接着Dispatch(()=> {; /来实现更好的初始响应/},DispatcherPriority.ApplicationIdle)。
在网络调用中使用异步事件处理程序和IProgress(您甚至不需要Dispatcher,只需更改绑定控件)会导致类似的进度更新,但初始响应可能是不可接受的。
使用同步等待会导致UI Paint停滞,使任何逐渐更新的进度条显得非常不稳定。
对我来说,进度条不稳定不是问题,因为我给操作员直接反馈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开始,它可能是半秒,甚至你看到发生了什么事情。
这几乎就像你希望短跑队队长能够击中秒表,或者和你一起跑。如果你试图ping两个10ms以下的网络,那么在工作中延迟50毫秒甚至开始似乎很多。但是,如果你有一个异常的那个,立即占用整个100毫秒等待而且STILL没有返回任何东西让你报告进度,那么在屏幕上放置一些东西真好。
感谢Cleary,我正在午餐后转向Reactive.NET。