最近有個項目需要每天固定的時間去執行指定的事件,發現網上關於這樣的文章比較少,而且比較散。通過學習了幾篇文章後終於實現了這個功能,在此也特別感謝這些文章的作者們,這也是我第一次在園子裡面發文章,望多指教。
關於觀察者模式,我在這裡就不做講解了,如有不懂,可以參考相關文章。
那麼開始入正題。
主要有三個頁面:Observer.cs(觀察者)、Subject.cs(通知者)、Form1.cs
Observer.cs
class Observer { /// <summary> /// 執行事件A /// </summary> /// <returns></returns> public string DoA() { return "時間到了,執行事件A~~"; } /// <summary> ///執行事件B /// </summary> /// <returns></returns> public string DoB() { return "時間到了,執行事件B~~"; } }
Subject.cs(用於通知觀察者的類)
namespace XXXXXX { //聲明委托 delegate string EventHandler(); class Subject { //聲明事件 public event EventHandler Output; public string Notify() { string res = ""; if (Output != null) { res = Output(); } return res; } } }
Form1.cs
使用了TextBox控件txtShow和Timer控件timer,timer的時間間隔設為1s
private void timer_Tick(object sender, EventArgs e) { Subject subject = new Subject(); Observer observer = new Observer(); string now = DateTime.Now.ToString("HH:mm:ss"); //設置固定時間要執行的事件 switch (now) { case "22:28:00": subject.Output += new EventHandler(observer.DoA); break; case "22:29:00": subject.Output += new EventHandler(observer.DoB); break; } string res = ""; //執行事件 res += subject.Notify(); if (res != "") { txtShow.AppendText(now + ":"); txtShow.AppendText(res); txtShow.AppendText("\r\n"); }
}
結果:
但以上的方法是同步的,也就是第一個方法執行太久的話會影響第二個方法的執行,那麼要解決這問題,下面就用到異步委托。
Observer.cs不用修改到,這也是用了觀察者模式所帶來的好處。
Subject.cs(修改了Notify方法,添加了一個委托、事件和方法)
namespace XXXX { //聲明委托 delegate string EventHandler(); delegate void ShowInfoHandler(string info); class Subject { //聲明事件 public event EventHandler Output; public event ShowInfoHandler ShowInfoEvent; public void Notify() { if (Output != null) { foreach(EventHandler handler in Output.GetInvocationList()) { //異步調用委托,第一個參數為要回調的函數,第二個參數為要向回調函數傳入的值 //這裡傳入被調用方法的委托 handler.BeginInvoke(CallBack, handler); } } } /// <summary> /// 回調函數 /// </summary> /// <param name="show"></param> public void CallBack(IAsyncResult obj) { EventHandler handler = (EventHandler)obj.AsyncState; //獲取被調用方法的返回的信息 string res= handler.EndInvoke(obj); ShowInfoEvent(res); } } }
這裡稍微解釋一下。ShowInfoHandler、ShowInfoEvent用於向主線程txtShow輸出提示信息用的,若不用輸出提示信息可以省去。(Form1.cs會用到)
handler.BeginInvoke調用異步委托,第一個參數傳入要回調的函數,也就是執行完自身的方法後會繼續執行的方法;第二個參數一般傳入自身的委托,方便在回調函數中獲取執行完返回的信息。
Form1.cs
//非主線程無法操作界面的控件,所以用委托來實現向txtShow輸出信息 public void ShowInfo(string info) { txtShow.Invoke(new Action(()=>{txtShow.AppendText(info+"\r\n");})); } private void timer_Tick(object sender, EventArgs e) { Subject subject = new Subject(); Observer observer = new Observer(); //將向txtShow輸出信息的方法交給subject的委托 subject.ShowInfoEvent += new ShowInfoHandler(ShowInfo); string now = DateTime.Now.ToString("HH:mm:ss"); switch (now) { case "23:20:00": txtShow.AppendText("現在時間:"+now+"\r\n"); subject.Output += new EventHandler(observer.DoA); break; case "23:21:00": txtShow.AppendText("現在時間:"+now+"\r\n"); subject.Output += new EventHandler(observer.DoB); break; } subject.Notify(); }
子線程操作主線程的控件還有其他方法,大家可以嘗試下,這裡就不整理了。
結果: