前 注:
这是自己平时根据自己需要写的一些小代码,未必对各看官有用。另外,这是根据个人想法而写,未必严谨和符合设计原则,若有任何不妥之处,还请不吝赐教。
说 明:
本文描述一个根据 《BusyTip——显示提示窗体的实现(一) 》中所述思路设计的一个用于显示提示窗体的功能接口的实现。本实现在一个守候线程上循环弹出模态对话框,并封装了触发弹出、关闭对话框事件的接口。
要 点:
1. TipThread为守候线程,线程方法为TipThreadRun。此方法在循环中等待ShowTipEvent事件,当该事件发生时弹出对话框,并进入阻塞状态;直到对话框关闭,然后线程开始等待下一次ShowTipEvent事件。
2. Start方法通过触发ShowTipEvent事件来通知TipThread显示对话框,Stop方法通过调用对话框的Close方法来关闭对话框。
3. Start、Stop与Monitor的Enter、Exit有些相似的特性:Start可以重复进入(效果不变),但调用多少次Start,就必须调用多少次Stop,才能合提示窗体关闭。
4. 可以使用SetProperty方法来设置提示窗体的属性,此方法使用反射与Invoke来实现其功能。BusyTipOperator.Text成员的set访问器是SetProperty("Text",value)的快捷形式。同样的,也可以为进度等其它数据添加类似属性。
5. 当State属性值为Released时,表示此BusyTipOperator对象已经释放其资源,不应再被使用。
示例:
for (int i = 0; i < 5; ++i) { busytip.Start(); busytip.Start(string.Format("循环:{0}...",i)); Thread.Sleep(1000); busytip.Stop(); //Thread.Sleep(100); busytip.Stop(); }
源 码:
using System; using System.Collections.Generic; using System.Text; using System.Threading; using System.Windows.Forms; using System.ComponentModel; namespace CommonLibrary.BusyTip { /// <summary> /// 调用委托 /// </summary> public delegate void DelegateInvoke(); /// <summary> /// 不考虑线程安全的设置属性委托 /// </summary> /// <param name="Value">属性值</param> public delegate void DelegateSetProperty(string PropertyName, object Value); /// <summary> /// 提示对象状态的枚举 /// </summary> public enum EnumBusyTipOperatorState { /// <summary> /// 正在显示提示窗体 /// </summary> Show, /// <summary> /// 空闲,未显示提示窗体 /// </summary> Free, /// <summary> /// 已释放,无法再显示提示窗体 /// </summary> Released }; /// <summary> /// 使用提示窗体的接口 /// </summary> public class BusyTipOperator:IDisposable { #region Constructor & Destructor /// <summary> /// 构造函数 /// </summary> public BusyTipOperator(Form tipDialog) { FrmTip = tipDialog; FrmTip.ShowInTaskbar = false; FrmTip.Load += new EventHandler(FrmTip_FormLoad); ShowTipEvent = new AutoResetEvent(false); FrmOpCompletedEvent = new AutoResetEvent(false); DelegateSetProperty = new DelegateSetProperty(this.SetProperty); TipThread = new Thread(new ThreadStart(this.TipThreadRun)); TipThread.Start(); } /// <summary> /// 析构函数 /// </summary> ~BusyTipOperator() { if (!Disposed) Dispose(); } #endregion #region Fields ///// <summary> ///// 显示的图片 ///// </summary> //public String _PictureAddress; ///// <summary> ///// 是否允许取消 ///// </summary> //public bool _CancelEnabled = true; ///// <summary> ///// 父窗体是否可用 ///// </summary> //public bool _ParentEnabled = false; ///// <summary> ///// 标记是否终止守护线程 ///// </summary> //public bool StopTipThread = false; /// <summary> /// 提示窗体 /// </summary> private Form FrmTip; /// <summary> /// 用于显示提示窗体的线程 /// </summary> private Thread TipThread; /// <summary> /// 触发显示提示窗体操作的事件 /// </summary> private AutoResetEvent ShowTipEvent; /// <summary> /// 此事件在窗体操作完成时发出通知 /// </summary> private AutoResetEvent FrmOpCompletedEvent; private DelegateSetProperty DelegateSetProperty; /// <summary> /// 当前提示的状态 /// </summary> private EnumBusyTipOperatorState _State = EnumBusyTipOperatorState.Free; /// <summary> /// 是否终止显示线程 /// </summary> private bool StopTipThread = false; /// <summary> /// 非托管资源释放标志 /// </summary> private bool Disposed = false; /// <summary> /// 锁,用于同步窗体的打开/关闭过程 /// </summary> private object Lock = new object(); /// <summary> /// 统计调用Start的嵌套层数(即当前需要调用Stop的次数) /// </summary> private int ShowCount = 0; #endregion #region Properties /// <summary> /// 当前提示窗体的状态 /// </summary> public EnumBusyTipOperatorState State { get { return _State; } } /// <summary> /// 提示内容 /// </summary> public string Text { get { return FrmTip.Text; } set { SetProperty("Text", value); } } /// <summary> /// 是否允许取消,此设置项暂时无效,默认为否 /// </summary> public bool CancelEnabled { get { return false; } set { } } /// <summary> /// 父窗体是否可用,此设置项暂时无效,默认为否 /// </summary> public bool ParentEnabled { get { return false ; } set { } } #endregion #region Operator Interface /// <summary> /// 开始显示提示窗体 /// </summary> public int Start() { Monitor.Enter(Lock); ++ShowCount; if (this.State == EnumBusyTipOperatorState.Free) { _State = EnumBusyTipOperatorState.Show; //通过ShowTipEvent事件向TipThread发送信息,使其显示提示窗体 ShowTipEvent.Set(); //等待提示窗体显示完成的信号 & 也可以通过以下方式实现:使当前线程挂起,然后在FrmTip_Load中恢复 FrmOpCompletedEvent.WaitOne(); } Monitor.Exit(Lock); return 1; } /// <summary> /// 开始显示提示窗体并在其中显示指定的提示文本 /// </summary> /// <param name="Text"></param> /// <returns></returns> public int Start(string Text) { this.Text = Text; return Start(); } /// <summary> /// 终止显示提示窗体 /// </summary> public int Stop() { Monitor.Enter(Lock); do { if (ShowCount <= 0) break; if (--ShowCount > 0) break; _State = EnumBusyTipOperatorState.Free; FrmTip.Invoke(new DelegateInvoke(FrmTip.Close)); FrmOpCompletedEvent.WaitOne(); } while (false); Monitor.Exit(Lock); return 1; } /// <summary> /// 设置提示窗体的提示文本 /// </summary> /// <param name="Text"></param> public void SetProperty(string PropertyName,object Value) { if (FrmTip.InvokeRequired) { FrmTip.Invoke(DelegateSetProperty, PropertyName, Value); } else { FrmTip.GetType().InvokeMember(PropertyName, System.Reflection.BindingFlags.SetProperty, null, FrmTip, new object[] { Value }); } } #endregion #region Innerl Methods /// <summary> /// 用来显示提示框的守护线程 /// </summary> private void TipThreadRun() { ShowTipEvent.WaitOne(); while (!StopTipThread) { FrmTip.ShowDialog(); FrmOpCompletedEvent.Set(); ShowTipEvent.WaitOne(); } } /// <summary> /// 释放非托管资源 /// </summary> public void Dispose() { Disposed = true; if (this.State == EnumBusyTipOperatorState.Show) Stop(); StopTipThread = true; ShowTipEvent.Set(); TipThread.Join(); _State = EnumBusyTipOperatorState.Released; } /// <summary> /// 提示窗体加载完成 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void FrmTip_FormLoad(object sender, EventArgs e) { FrmOpCompletedEvent.Set(); } #endregion } }