2012-09-15 27 views
4

我有一個DispatcherTimer在我的代碼中運行,每隔30秒觸發一次以更新服務器的系統狀態。即使我正在調試我的服務器代碼,計時器也會在客戶端觸發,所以如果我已經調試了5分鐘,我可能會在客戶端中產生一打超時。最後決定我需要解決這個問題,這樣看起來更友好的DispatcherTimer。在DispatcherTimer運行異步友好DispatcherTimer包裝器/子類

  • 代碼必須是可配置無論是折返的或不(即,如果該任務已經運行它不應該嘗試再次運行)
  • 應根據任務(這是否需要我實際上暴露任務的根是一個灰色區域)
  • 應該能夠運行在任務異步代碼和await完成
  • 無論是包裝還是擴展DispatcherTimer可能並不重要,但其包裝可能會略有減少曖昧如果你不知道如何使用它
  • 爲UI可能暴露IsRunning的可綁定屬性
+0

你看過'Task.Delay()'嗎? – svick

+0

@svick不太清楚你的意思,除非你在談論某種類型的無限循環,但接下來會在哪裏運行 –

+0

是的,我的意思是像無限循環。如果你從UI線程「等待」它,那麼它也會在那裏恢復。你可以從'async void'方法調用它,這意味着它將獨立於調用它的代碼運行。 – svick

回答

10

下面是我想到的。

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

下面的代碼。想聽聽任何想法

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; } 
} 
+0

它對我很好。 –

+1

這是一個很好的解決方案,直到現在我都沒有找到更好的解決方案。我們實施了類似的東西但棘手的部分來,如果你想停止計時器,並確保任務完成:) –