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

Sim*_*ver 4 c# wpf asynchronous dispatchertimer .net-4.5

DispatcherTimer在我的代码中运行,每30秒触发一次,从服务器更新系统状态.即使我正在调试我的服务器代码,计时器也会在客户端中触发,因此如果我已经调试了5分钟,我可能会在客户端中进行十几次超时.最后决定我需要修复这个问题从而寻求使一个更加async/ await友好DispatcherTimer.

  • 运行的代码DispatcherTimer必须是可配置的,无论它是否是可重入的(即如果任务已经运行,则不应该再次运行它)
  • 应该是基于任务的(无论这是否要求我实际上在根处暴露任务是一个灰色区域)
  • 应该能够运行异步代码和await完成任务
  • 无论是包装还是扩展DispatcherTimer可能并不重要,但如果你不知道如何使用它,包装它可能会稍微不那么模糊
  • 可能IsRunning为UI提供可绑定属性

Sim*_*ver 11

这就是我想出来的.

  • SmartDispatcherTimer扩展DispatcherTimer(最简单的方法来启动和运行)
  • 有一个TickTask属性来提供一个Task处理逻辑
  • 有一个IsReentrant属性(当然,重点是我希望它不是可重入的,所以通常这是假的)
  • 它假定您所称的任何内容都是完全等待的 - 或者您最终会失去可重入保护权益

用法:

        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();
Run Code Online (Sandbox Code Playgroud)

这是代码.很想听听它的任何想法

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; }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的解决方案,到目前为止我还没有找到更好的东西.我们实施了类似的东西 但是如果你想要停止计时器并确保任务完成,那就很棘手了:) (2认同)