Delayed Dispatch Invoke?

╄→гoц情女王★ 提交于 2019-12-04 23:04:04

I wouldn't assume that the DispatcherTimer is heavy-weight... why not just write an extension method on Dispatcher which allows you to use the syntax you want, and uses a DispatcherTimer in the background? I would personally call it DelayInvoke rather than BeginInvoke though... and I'd also fix it to always use Action rather than an arbitrary delegate... that will make it easier to use lambda expressions:

Dispatcher.DelayInvoke(TimeSpan.FromMilliseconds(200), () => { ... 
});

(I tend to find it's more readable if anonymous functions are used as the final argument in a method call, but that's just a personal preference.)

Given that you'll quite possibly want to use milliseconds most of the time, you could have another helper method too:

Dispatcher.DelayInvokeMillis(200, () => { ... 
});

Another alternative to try is merely to use the existing BeginInvoke method but with a very low priority, so your delegate will only be invoked after everything else has finished. Without knowing the details of your situation, it's hard to know whether that'll work or not - but it's worth trying.

A .NET 4.5 way:

    public async void MyMethod()
    {
        await Task.Delay(20); 
        await Dispatcher.BeginInvoke((Action)DoStuff);
    }

I'm not fond of the DispatcherTimer because there is no easy way to pass parameters in other than through function scope/closures.

Instead I use a Task.Delay() and wrap that into a Dispatcher.Delay() extension method:

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

To call this then:

Dispatcher.Delay(4000, (win) =>
{
     var window = win as MainWindow;
     window.ShowStatus(null, 0);
},this);

You might be able to use the Paul Stowell's DelayBinding class from here: http://www.paulstovell.com/wpf-delaybinding.

With this can can bind to a DependencyProperty on a class that can execute the action when the property changes. The binding will manage the delay. Might be particularly nice if you have a MVVM-type design.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!