wpf 异步友好 DispatcherTimer 包装器/子类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12442622/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 05:22:43  来源:igfitidea点击:

Async friendly DispatcherTimer wrapper/subclass

c#wpfasynchronous.net-4.5dispatchertimer

提问by Simon_Weaver

I have a DispatcherTimerrunning in my code that fire every 30 seconds to update system status from the server. The timer fires in the client even if I'm debugging my server code so if I've been debugging for 5 minutes I may end up with a dozen timeouts in the client. Finally decided I needed to fix this so looking to make a more async/ awaitfriendly DispatcherTimer.

DispatcherTimer在我的代码中运行,每 30 秒触发一次以从服务器更新系统状态。即使我正在调试我的服务器代码,计时器也会在客户端触发,所以如果我已经调试了 5 分钟,我可能会在客户端出现十几个超时。最后决定我需要解决这个问题,所以希望制作一个更async/await友好的 DispatcherTimer。

  • Code running in DispatcherTimermust be configurable whether it is reentrant or not (i.e. if the task is already running it should not try to run it again)
  • Should be task based (whether or not this requires I actually expose Task at the root is a gray area)
  • Should be able to run async code and awaiton tasks to complete
  • Whether it wraps or extends DispatcherTimer probably doesn't really matter but wrapping it may be slightly less ambiguous if you don't know how to use it
  • Possibly expose bindable properties for IsRunningfor UI
  • DispatcherTimer无论是否可重入,运行的代码都必须是可配置的(即,如果任务已经在运行,则不应尝试再次运行它)
  • 应该是基于任务的(无论这是否需要我在根部实际公开 Task 是一个灰色区域)
  • 应该能够运行异步代码并await完成任务
  • 它是否包装或扩展 DispatcherTimer 可能并不重要,但如果您不知道如何使用它,包装它可能会稍微不那么模糊
  • 可能IsRunning为 UI公开可绑定属性

回答by Simon_Weaver

Here's what I came up with.

这是我想出的。

  • SmartDispatcherTimerExtends DispatcherTimer(was easiest way to get this up and running)
  • Has a TickTaskproperty to provide a Taskto handle the logic
  • Has an IsReentrantproperty (of course the whole point is that I want it to not be reentrant so normally this is false)
  • It assumes anything you're calling is fully awaitable - or you'd end up losing the reentrancy protection benefits
  • SmartDispatcherTimer扩展DispatcherTimer(是启动和运行的最简单方法)
  • 有一个TickTask属性来提供一个Task来处理逻辑
  • 有一个IsReentrant属性(当然,重点是我希望它不能重入,所以通常这是错误的)
  • 它假设您调用的任何内容都是完全可等待的 - 否则您最终将失去重入保护的好处

Usage:

用法:

        var timer = new SmartDispatcherTimer();
        timer.IsReentrant = false;
        timer.Interval = TimeSpan.FromSeconds(30);
        timer.TickTask = async () =>
        {
            StatusMessage = "Updating...";  // MVVM property
            await UpdateSystemStatus(false);
            StatusMessage = "Updated at " + DateTime.Now;
        };
        timer.Start();

Here's the code. Would love to hear any thoughts on it

这是代码。很想听听关于它的任何想法

public class SmartDispatcherTimer : DispatcherTimer
{
    public SmartDispatcherTimer()
    {
        base.Tick += SmartDispatcherTimer_Tick;
    }

    async void SmartDispatcherTimer_Tick(object sender, EventArgs e)
    {
        if (TickTask == null)
        {
            Debug.WriteLine("No task set!");
            return;
        }

        if (IsRunning && !IsReentrant)
        {
            // previous task hasn't completed
            Debug.WriteLine("Task already running");
            return;
        }

        try
        {
            // we're running it now
            IsRunning = true;

            Debug.WriteLine("Running Task");
            await TickTask.Invoke();
            Debug.WriteLine("Task Completed");
        }
        catch (Exception)
        {
            Debug.WriteLine("Task Failed");
        }
        finally
        {
            // allow it to run again
            IsRunning = false;
        }
    }

    public bool IsReentrant { get; set; }
    public bool IsRunning { get; private set; }

    public Func<Task> TickTask { get; set; }
}