2011年11月22日 星期二

把 Timer 當 postDelayed 用的方法

之前在寫 .Net 的專案時若需要用到 Timer 常常會直接使用 DispatcherTimer
官方文件:System.Windows.Threading.DispatcherTimer
使用方法在文件中有很詳細的介紹…

而我之所以習慣用這個 Timer 是因為與 Windows API、Java 中的 Timer 觀念很類似…
在 Android 中我們如果要限制用戶一些無意義的連擊動作對效能造成負擔…
常常會使用 postDelayed + removeCallbacks 來實作…
最近在 Windows Phone 的專案中也要加入類似的功能…於是看到這個類別
System.Threading.Timer
雖然用 DispatcherTimer 也可以做到一樣的行為…但個人覺得使用 Timer 更為簡單乾淨…

此 Timer 在建構式與 Change Method 各有兩個數值型態的參數…
dueTime 的範圍是正整數值或 Timeout.Infinite (-1)
這個值代表 Timer 在啟動後多少毫秒後執行 callback method
0 代表立即執行…若為 Timeout.Infinite 代表不執行…
period 的範圍同樣是正整數值或 Timeout.Infinite (-1)
此值代表多少毫秒為一個循環…若是 0 或 Timeout.Infinite 皆表示不循環…

這樣子看起來還蠻適合拿來當作 postDelayed 這種方法使用…
假設我們有一個列表在點下某列後要開始運算一些資料…
我們不想要在用戶快速的亂點時每次都做運算…
所以我們做一個 0.5 秒的 Delay 時間…
若在 0.5 秒內用戶改變心意則使用新的一列當作運算資料的值…簡單的範例如下…


public class SelectionPage : PhoneApplicationPage
{
    public volatile int mIndex = -1;
    private Timer timer = null;
 
    public SelectionPage()
    {
        InitializeComponent();
    }

    // 假設有一個 ListBox 並在此處理 SelectionChanged 事件
    private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        // 例如點擊某列就要去遠端取某列的地點之一週氣像資訊
        int nIndex = ((ListBox)sender).SelectedIndex;
        HandleSelected(nIndex);
    }

    private void HandleSelected(int nIndex)
    {
        mIndex = nIndex;
        if (timer == null)
        {
            timer = new Timer(new TimerCallback(OnTimerTick), null, 500, Timeout.Infinite);
        }
        else
        {
            // 取消上次的 Delay
            timer.Change(Timeout.Infinite, Timeout.Infinite);
            // 重新計算 500 毫秒
            timer.Change(500, Timeout.Infinite);
        }
    }

    private void OnTimerTick(object obj)
    {
        // 拿 mIndex 開始做事
    }
}


如果要在 OnTimerTick 中修改 Layout Property
則要記得使用 System.Windows.Deployment.Current.Dispatcher.BeginInvoke 唷
而若是 DispatcherTimer 就不用了…因為已經是在 UI Thread 嘍…

沒有留言:

張貼留言