在上文《我的界面进度条异步显示模式》中,我提到了使用异步处理显示进度条的时候,我觉得用起来比较顺手的一种组织代码的方法,相比起来,这种方法的最大特点就是把代码尽量地从界面层剥离,并且让界面之间的关联尽可能少些。

我在处理过程中使用了一个封装了异步线程处理的一个抽象类,这个抽象类实现了异步处理的 Start,Abort, Pause 和 Resume 接口,大家用它来实现异步处理的时候,就可以象玩秒表一样随意地控制这些处理过程了。完整的代码如下:

public abstract class AsyncWorker
     { 
 
         public enum WorkState{Ready, Working, Pause,Resume,Aborted, Done, Error}        private WorkState m_State;
         private bool m_Wait;
         private Thread m_Thread;        protected AsyncWorker(bool wait)
         { 
 
             m_State = WorkState.Ready;
             m_Wait = wait;
             m_Thread = new Thread(new ThreadStart(Work));
         }        public void Start()
         { 
 
             OnStateChangedSync(WorkState.Ready);
             m_Thread.Start();
             while( m_Wait && m_Thread.IsAlive )
             { 
 
                 OnIdle();
                 Thread.Sleep(200);
             }
         }        public void Pause()
         { 
 
             if( m_State == WorkState.Working)
             { 
 
                 m_Thread.Suspend();
                 m_State = WorkState.Pause;
                 OnStateChanged(WorkState.Pause);
             }
         }        public void Resume()
         { 
 
             if( m_State == WorkState.Pause )
             { 
 
                 m_State = WorkState.Working;
                 m_Thread.Resume();
                 OnStateChanged(WorkState.Resume);
             }
         }        public void Abort()
         { 
 
             if( m_State == WorkState.Working || m_State == WorkState.Pause )
             { 
 
                 m_Thread.Abort();
                 m_State = WorkState.Aborted;
                 OnStateChanged(WorkState.Aborted);
             }
         }        private void Work()
         { 
 
             try
             { 
 
                 m_State = WorkState.Working;
                 OnStateChangedSync(WorkState.Working);                DoWork();
                m_State = WorkState.Done;
                 OnStateChanged(WorkState.Done);
             }
             catch (Exception e)
             { 
 
                 m_State = WorkState.Error;
                 OnError(e);
                 OnStateChanged(WorkState.Error);
             }
         }        protected abstract void DoWork();
        private void OnStateChangedSync(WorkState state)
         { 
 
             if( StateChanged != null )
                 StateChanged(this, state);
         }        private void OnStateChanged(WorkState state)
         { 
 
             if( StateChanged != null )
                 StateChanged.BeginInvoke(this, state, null, null);
         }        protected void OnIdle()
         { 
 
             if( Idle != null )
             { 
 
                 lock(this)        // 有可能会很高频率调用
                     Idle(this);
             }
         }        protected void OnError(Exception e)
         { 
 
             if( Error != null )
                 Error.BeginInvoke(this, e, null, null);
         }        public delegate void StateChangedEventHandler(AsyncWorker sender, WorkState state);
         public delegate void IdleEventHandler(AsyncWorker sender);
         public delegate void ErrorEventHandler(AsyncWorker sender, Exception e);        public event StateChangedEventHandler StateChanged;
         public event IdleEventHandler Idle;
         public event ErrorEventHandler Error;
     }

在处理进度变化的时候,我使用了一个抽象的接口 IProgress,这个抽象接口提供外部对进度的查询功能,接口定义如下:

/** <summary>
     /// 反映进度的变化的接口
     /// </summary>
     public interface IProgress
     { 
 
         int Total{get;}
         int CurrentProgress{get;}
         string Description{get;}
     }

在具体实现的时候,可以看我的 ProgressMoniter 的代码,这个是利用一个单独的线程来定期轮询 IProgress 接口进度变化,然后产生事件通知,是最好的说明例子,如果有人想修改成非轮询的方式,也很容易。

public class ProgressMoniter : AsyncWorker
     { 
 
         public delegate void ProgressEventHandler(string text, int percent);        public event ProgressEventHandler Progress;
        IProgress m_Progress;
         private bool m_Exit;        public bool Exit { get { return m_Exit; } set { m_Exit = value; } }
        public ProgressMoniter(IProgress progress) : base(false)
         { 
 
             m_Progress = progress;
             m_Exit = false;
         }        protected override void DoWork()
         { 
 
             while( !m_Exit )
             { 
 
                 lock(m_Progress)
                     OnProgress(m_Progress.Description, m_Progress.Total, m_Progress.CurrentProgress);
                 Thread.Sleep(200);
             }
         }        private void OnProgress(string description, int total, int progress)
         { 
 
             if( Progress != null )
                 Progress.BeginInvoke(description, (int)((long)progress * 100 / (long)total), null, null);
         }
     }