最近有个项目需要每天固定的时间去执行指定的事件,发现网上关于这样的文章比较少,而且比较散。通过学习了几篇文章后终于实现了这个功能,在此也特别感谢这些文章的作者们,这也是我第一次在园子里面发文章,望多指教。
关于观察者模式,我在这里就不做讲解了,如有不懂,可以参考相关文章。
那么开始入正题。
主要有三个页面: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(); }
子线程操作主线程的控件还有其他方法,大家可以尝试下,这里就不整理了。
结果: