2010-09-18 153 views
10

在WPF中,由於界面更新的複雜性,我有時必須在短暫的延遲後執行操作。延遲調度調用?

目前我只是做這個:(?)

 var dt = new DispatcherTimer(DispatcherPriority.Send); 
     dt.Tick += (s, e) => 
     { 
      dt.Stop(); 
      //DoStuff 
     }; 
     dt.Interval = TimeSpan.FromMilliseconds(200); 
     dt.Start(); 

但它是既有點難看,也許太多的開銷每次創建一個新的計時器 什麼是從性能的角度來最好這樣做,即執行最迅速?什麼是改寫上面的代碼到類似好辦法:

 this.Dispatcher.BeginInvoke(new Action(delegate() 
     { 
      //DoStuff 
     }), DispatcherPriority.Send,TimeSpan.FromMilliseconds(200)); 

如果時間跨度是延遲,感謝您的任何輸入:)

+0

而不是更新前等待的東西,你能不能動責任將UI更新爲您正在等待的東西?這會避免定時器。 – x0n 2010-09-18 08:09:19

+0

不幸的是,它是很酷的東西,如更新用戶界面並在短暫的延遲後隱藏它,所以當窗口再次顯示時更新窗口 – Homde 2010-09-18 08:26:03

回答

11

我不會假設DispatcherTimer是重量級...爲什麼不在Dispatcher上寫一個擴展方法,它允許你使用你想要的語法,並在後臺使用DispatcherTimer?我個人把它DelayInvoke,而不是BeginInvoke雖然...我也想解決它總是使用Action而非任意委託...這將使它更容易使用lambda表達式:

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

(如果匿名函數被用作方法調用的最後一個參數,我傾向於發現它更具可讀性,但這只是個人偏好。)

鑑於您很可能希望在大多數時間使用毫秒,可以有另一種幫手方法:

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

嘗試的另一種替代方法是僅使用現有的BeginInvoke方法,但優先級很低,因此只有在其他所有操作完成後纔會調用委託。在不瞭解情況的細節的情況下,很難確定這種情況是否有效,但值得嘗試。

+0

擴展方法將是非常好的,但是這並不意味着我首先必須做一個begininvoke讓調度員在正確的線程上,然後設置計時器,這比只有計時器的開銷稍高一點?可能不是一個問題,但... – Homde 2010-09-18 08:32:46

+0

@MattiasK:爲什麼需要這樣做?它根本不需要與調度員進行交互......這只是爲了保持一致性。無可否認,我不知道如果從另一個線程創建DispatcherTimer會發生什麼......但如果它直接完成工作,它將從擴展方法起作用,而沒有任何額外的問題。 – 2010-09-18 08:43:00

+2

@MattiasK:我剛剛檢查過,你可以告訴DispatcherTimer的構造函數應該運行哪個Dispatcher - 所以你可以使用擴展方法的重載,並指定已經傳遞給方法的Dispatcher。 – 2010-09-18 09:02:13

0

您可以從這裏使用Paul Stowell的DelayBinding類:http://www.paulstovell.com/wpf-delaybinding

這可以綁定到DependencyProperty上的一個類,當屬性更改時可以執行操作。綁定將管理延遲。 如果您有MVVM型設計,可能會特別好。

3

一個.NET 4.5的方式:

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

我不喜歡的DispatcherTimer的,因爲是通過在其他參數不是通過功能範圍/關閉沒有簡單的方法。

相反,我使用了一個Task.Delay()和換行到一個Dispatcher.Delay()擴展方法:

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

爲了然後調用此:

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