Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 延迟调度调用?_.net_Wpf_Dispatcher - Fatal编程技术网

.net 延迟调度调用?

.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

在WPF中,由于界面更新的复杂性,我有时不得不在短时间延迟后执行操作

目前,我只是通过以下方式来实现:

        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);