.net 延迟调度调用?
在WPF中,由于界面更新的复杂性,我有时不得不在短时间延迟后执行操作 目前,我只是通过以下方式来实现:.net 延迟调度调用?,.net,wpf,dispatcher,.net,Wpf,Dispatcher,在WPF中,由于界面更新的复杂性,我有时不得不在短时间延迟后执行操作 目前,我只是通过以下方式来实现: var dt = new DispatcherTimer(DispatcherPriority.Send); dt.Tick += (s, e) => { dt.Stop(); //DoStuff }; dt.Interval = TimeSpan.FromMi
var dt = new DispatcherTimer(DispatcherPriority.Send);
dt.Tick += (s, e) =>
{
dt.Stop();
//DoStuff
};
dt.Interval = TimeSpan.FromMilliseconds(200);
dt.Start();
但是每次创建一个新的计时器都有点难看,而且可能开销太大(?)
从性能的角度来看,什么是最好的(最迅速地执行)?还有什么好方法可以将上述代码重写为:
this.Dispatcher.BeginInvoke(new Action(delegate()
{
//DoStuff
}), DispatcherPriority.Send,TimeSpan.FromMilliseconds(200));
其中Timespan是延迟,感谢您的任何输入:)我不会假设调度程序的重量很重。。。为什么不在Dispatcher
上编写一个扩展方法,允许您使用所需的语法,并在后台使用dispatchermer
?我个人称之为DelayInvoke
,而不是BeginInvoke
。。。我还将修正它,使其始终使用操作
而不是任意委托。。。这将更容易使用lambda表达式:
Dispatcher.DelayInvoke(TimeSpan.FromMilliseconds(200), () => { ...
});
(我倾向于发现,如果在方法调用中使用匿名函数作为最终参数,则可读性更高,但这只是个人偏好。)
考虑到您很可能在大多数情况下都希望使用毫秒,您也可以使用另一个helper方法:
Dispatcher.DelayInvokeMillis(200, () => { ...
});
另一种尝试方法是仅使用现有的BeginInvoke
方法,但优先级非常低,因此只有在完成所有其他操作后才会调用您的委托。如果不了解您的具体情况,很难知道这是否有效,但值得一试。您可以从这里使用Paul Stowell的DelayBinding类:
使用此选项,可以绑定到类上的DependencyProperty,该类可以在属性更改时执行操作。绑定将管理延迟。
如果您有MVVM类型的设计,可能会特别好。a.NET 4.5方式:
public async void MyMethod()
{
await Task.Delay(20);
await Dispatcher.BeginInvoke((Action)DoStuff);
}
我不喜欢Dispatcher,因为除了通过函数作用域/闭包之外,没有其他简单的方法来传递参数
相反,我使用Task.Delay()
并将其包装到Dispatcher.Delay()
扩展方法中:
public static class DispatcherExtensions
{
public static void Delay(this Dispatcher disp, int delayMs,
Action<object> action, object parm = null)
{
var ignore = Task.Delay(delayMs).ContinueWith((t) =>
{
disp.Invoke(action, parm);
});
}
public static void DelayWithPriority(this Dispatcher disp, int delayMs,
Action<object> action, object parm = null,
DispatcherPriority priority = DispatcherPriority.ApplicationIdle)
{
var ignore = Task.Delay(delayMs).ContinueWith((t) =>
{
disp.BeginInvoke(action, priority, parm);
});
}
public static async Task DelayAsync(this Dispatcher disp, int delayMs,
Action<object> action, object parm = null,
DispatcherPriority priority = DispatcherPriority.ApplicationIdle)
{
await Task.Delay(delayMs);
await disp.BeginInvoke(action, priority, parm);
}
}
你不能把更新UI的责任转移到你正在等待的事情上,而不是在更新之前等待什么吗?这将避免使用计时器。不幸的是,这是一种黑客行为,比如更新ui并在短暂延迟后隐藏它,这样当它再次显示时窗口会更新,这让我感觉更好,因为很多其他人都有和我一样的问题和相同的黑客解决方案。扩展方法会非常好,但是,这难道不意味着我必须首先在调度程序上做一个begininvoke,使其处于正确的线程上,然后设置计时器,这比只设置计时器的开销要大一点吗?但这可能不是问题…@MattiasK:为什么需要这样做?它根本不需要和调度员互动。。。这只是为了保持一致性。诚然,我不知道如果你从一个不同的线程创建一个Dispatchermer会发生什么。。。但是,如果直接执行,它将在扩展方法中运行,而不会产生任何额外问题。@MattiasK:我刚刚检查过,您可以告诉Dispatchermer构造函数它应该在哪个Dispatcher上运行-因此您可以使用扩展方法中的重载,并指定已传递给该方法的调度程序。与上面的计时器方法相比,它的优点和缺点?更简单,因为它不需要lambda。。。很可能就是这样。非常简洁的解决方案。你能详细说明一下使用Task.Delay和定时器的优缺点吗?你关心的仅仅是传递论点的能力吗?
Dispatcher.Delay(4000, (win) =>
{
var window = win as MainWindow;
window.ShowStatus(null, 0);
},this);