2009年10月17日 星期六

C# --Experience Timer Control Logic

最近正在進行一個RS-485通信資料的專案, 其中用到了常用到的Timer Control
原來的流程是這樣的..
step 1. 開啟Timer --> Timer1.Enabled = true
step 2. 等待Timer1_Tick事件觸發
step 3. 進入到Timer1_Tick事件後,由於不確定在這個Timer1_Tick事件中程式要執行多久才能將所有工作執行完畢. 所以在進入 Timer1_Tick事件後的第一件事就是將 Timer1.Enable 設定成false. 這樣理論上就能確保在Timer1_Tick 事件程序中的工作能完整的被執行完後才離開.
step 4. 當在Timer1_Tick事件程序中的工作都完成後便再將Timer1.Enable 設定成true. 這是為了讓Timer繼續的去執行. 之後程式就等待下一個Timer1_Tick事件被觸發.

當然,為了能夠提供使用者能自己控制這個 Timer1是否要開始計時, 所以在UI上得要提供一個Button來讓使用者操作Timer的Enable 為 true 或是false.
簡單的做法便是在Button_Click事件程序中寫一行:
Timer1.Enabled = !Timer1.Enabled.

經過以上的邏輯之後會發現好像就如同這麼簡單的方式可以被完成...

但, 是不幸的是... 上述的邏輯是不能被正常的完成上述所期望的工作.
經過執行的結果會發現.. 這個程式的Timer能被Enable 但無法被Disable.

原因是因為, Windows的程式是事件觸發.基本上,程式是一直處在一個等待的狀態. 而這個狀態除了是等待Timer1_Tick事件觸發之外,也等待使用者操作Button.. 等待Button_Click事件觸發.

在這個例子裡頭,原先所假定的Timer的Enable 或是 Disable 是透過Button_Click裡的 Timer1.Enabled = !Timer1.Enabled.
但是, 當使用者按下Button的同時, 程式有可能正在執行Timer1_Tick程序中的程式. 在這個Timer1_Tick程序中的最後一個步驟是... Timer1.Enabled = true;
所以會發生:

1.當使用者按下Button後, Button_Click程序中執行了Timer1.Enabled = !Timer1.Enabled (這裡先假定原先Timer1.Enabled = true 而在經過 !Timer1.Enable 則 Timer1.Enabled = false) 這表示.. 當使用者按下後Timer會被停止.
2. 在此同時,Timer1_Click事件被觸發了.. 第一個步驟是Timer1.Enabled = false (停止Timer)
3. 執行Timer1_Tick中所有的程式.
4.執行到最後一個步驟時.. Timer1.Enabled 要被設定成為true. (可是.. 之前我們明明己經按下Button讓Timer設定為停止的狀態) 這會兒又被設定為true. 結果就是真的執行的沒完沒了的.. 程式打死都停不下來.

要解決這個問題需要做些邏輯上的調整:
step 1. 開啟Timer --> Timer1.Enabled = true
step 2. 等待Timer1_Tick事件觸發
step 3. 進入到Timer1_Tick事件後,由於不確定在這個Timer1_Tick事件中程式要執行多久才能將所有工作執行完畢. 所以在進入 Timer1_Tick事件後的第一件事就是將 Timer1.Interval 設定成一個超長的時間. 這樣理論上就能確保在Timer1_Tick 事件程序中的工作能完整的被執行完後才會觸發下一個Timer_Tick事件.
step 4. 當在Timer1_Tick事件程序中的工作都完成後便再將Timer1.Interval 設定成一個超長的時間設定為"一個原先正常的時間" e.g 1000. 這是為了讓Timer繼續的去執行. 之後程式就等待下一個Timer1_Tick事件被觸發.

經過上述的邏輯調整後就能維持原來在Button_Click中的Timer.Enable=!Timer1.Enabled 的Timer啟停控制的機制.

這算是... 邏輯上的"誤區"吧...

沒有留言:

張貼留言