.NET:延迟后执行的UI线程的lambda最佳方式吗?线程、方式、NET、UI

2023-09-04 00:24:00 作者:爱到深处___心会碎

我有一个情况上来,需要延迟一段时间后运行UI线程上的lambda EX pression。我想到了几种方法可以做到这一点,终于在这个方法

I had a situation come up that required running a lambda expression on the UI thread after a delay. I thought of several ways to do this and finally settled on this approach

Task.Factory.StartNew(() => Thread.Sleep(1000))
    .ContinueWith((t) => textBlock.Text="Done",TaskScheduler.FromCurrentSynchronizationContext());

但我不知道是否有一个更简单的方法,我错过了。任何建议较短,较简单或更方便的技术?假设.NET 4中是可用的。

But I'm wondering if there's an easier way that I missed. Any suggestions for a shorter, simpler or easier technique? Assume .NET 4 is available.

推荐答案

我觉得你得到的是pretty的好斯科特。

I think what you've got is pretty good Scott.

唯一的小问题,我觉得有些人可能有它,是你阻止一个线程,以执行你的延迟。当然,这是一个后台线程,并不会造成问题,除非你执行了很多这些调用兼任(每占用一个线程),但它仍然可能不理想。

The only slight issue I think some might have with it, is that you're blocking a thread in order to execute your delay. Of course it's a background thread, and unlikely to cause problems unless you execute a lot of these calls concurrently (each tying up a thread), but it's still probably suboptimal.

我反而建议大家因素算法到一个实用的方法,并避免使用Thread.sleep代码。

I would instead suggest that you factor the algorithm into a utility method, and avoid using Thread.Sleep.

有明显这样做的可能是无数的方式,但这里有一个:

There's obviously probably innumerable ways of doing this, but here's one:

public static class UICallbackTimer
{
    public static void DelayExecution(TimeSpan delay, Action action)
    {
        System.Threading.Timer timer = null;
        SynchronizationContext context = SynchronizationContext.Current;

        timer = new System.Threading.Timer(
            (ignore) =>
            {
                timer.Dispose();

                context.Post(ignore2 => action(), null);
            }, null, delay, TimeSpan.FromMilliseconds(-1));
    }
}

要使用:

    UICallbackTimer.DelayExecution(TimeSpan.FromSeconds(1),
        () => textBlock.Text="Done");

当然,你也可以这样写,它使用其他类型的定时器,如WPF DispatcherTimer或WinForms的Timer类此DelayExecution方法的实现。我不知道这些不同的定时器的权衡会。我的猜测是DispatcherTimer的和的WinForm的定时器实际上仍然在发挥作用相反类型的应用程序。

Of course you could also write an implementation of this DelayExecution method which uses other types of timer such as the WPF DispatcherTimer or the WinForms Timer class. I'm not sure what the tradeoffs of these various timers would be. My guess would be DispatcherTimer's and WinForm's timers would actually still function on applications of the opposite type.

编辑:

重读我的回答,我觉得其实我会受到诱惑而这一因素在其中工作在同步上下文扩展方法 - 如果你想想看,一个更普遍的说法是,你需要能够发布工作回到一定延迟后的同步上下文

Re-reading my answer, I think actually I would be tempted to factor this into an extension method which works on synchronization contexts - if you think about it, a more general statement would be that you need to be able to post work back to a synchronization context after a certain delay.

本的SynchronizationContext已经有一个POST方法排队的工作,这在原主叫方不希望阻止上完成。我们需要的是一个延迟后的版本,这是岗位工作的,所以不是:

The SynchronizationContext already has a post method for queueing work, which the original caller does not want to block on completion. What we need is a version of this that posts the work after a delay, so instead:

public static class SyncContextExtensions
{
    public static void Post(this SynchronizationContext context, TimeSpan delay, Action action)
    {
        System.Threading.Timer timer = null;

        timer = new System.Threading.Timer(
            (ignore) =>
            {
                timer.Dispose();

                context.Post(ignore2 => action(), null);
            }, null, delay, TimeSpan.FromMilliseconds(-1));
    }
}

和使用说明:

        SynchronizationContext.Current.Post(TimeSpan.FromSeconds(1),
            () => textBlock.Text="Done");