對進度條的通用封裝實現

          一直想寫點啥對最近的工作做個總結,由於項目比較忙,可能還有自己的各種理由推脫有點懈怠,零碎的總結過一些,都沒有動筆寫下來過。眼看2013都要過去了,該寫點啥來總結下。先從自己對進度封裝的一點學習經驗寫出來,供大家交流,歡迎園子裏的朋友不吝嗇的拍磚。

         首先定義對進度表示的契約,定義進度行爲(IProgressor)、進度信息(IStepProgress)和中斷處理(ITrackCancel)的接口如下:

    /// <summary>
    /// 進度行爲接口
    /// </summary>
    public interface IProgressor
    {
        string Message { get; set; }
        void Show();
        void Hide();
        void Step();
    }
     /// <summary>
    /// 進度展示接口
    /// </summary>
    public interface IStepProgress : IProgressor
    {
        int MaxRange { get; set; }
        int MinRange { get; set; }
        int StepValue { get; set; }
        i
    /// <summary>
    /// 中斷接口
    /// </summary>
    public interface ITrackCancel
    {
        void Cancel();
        bool Continue();
        bool CancelOnClick { get; set; }
        bool CancelOnKeyPress { get; set; }

        IProgressor Progressor { get; set; }
    }

          實現進度信息接口,實現類(ProgressBarDialog)如下:

    /// <summary>
    /// 進度實現類
    /// </summary>
    public class ProgressBarDialog:IStepProgress
    {
        
        private int maxRange;
        private int minRange;
        private int stepValue;
        private int position;
        private string message;
        private Task task;
        private ProgressBarForm progressBarForm;
        private CancellationTokenSource cancellationTokenSource;
        private ITrackCancel trackCancel;


        public Form ParentForm { get; set; }


        public ITrackCancel TrackCancel
        {
            get { return trackCancel; }
            set 
            {
                if (value != null)
                {
                    trackCancel = value;
                    trackCancel.Progressor = this;
                }
                if(progressBarForm != null)
                    progressBarForm.TrackCancel = value;
                
            }
        }

        public int MaxRange
        {
            get { return maxRange; }
            set
            {
                if (maxRange != value)
                {
                    if (progressBarForm != null)
                        progressBarForm.MaxRange = value;
                    maxRange = value;
                }
            }
        }


        public int MinRange
        {
            get { return minRange; }
            set
            {
                if (minRange != value)
                {
                    if(progressBarForm != null)
                        progressBarForm.MinRange = value;
                    minRange = value;
                }
            }
        }

        public int StepValue
        {
            get { return stepValue; }
            set
            {
                if (stepValue != value)
                {
                    if (progressBarForm != null)
                        progressBarForm.StepValue = value;
                    stepValue = value;
                }
            }
        }

        public int Position
        {
            get { return position; }
            set 
            {
                if (progressBarForm != null)
                    progressBarForm.Position = value;
                position = value;
            }
        }

        public string Message
        {
            get { return message; }
            set
            {
                if (message != value)
                {
                    if (progressBarForm != null)
                        progressBarForm.Message = value;
                    message = value;
                }
            }
        }

        private void InitDialog()
        {
            if (progressBarForm == null)
                progressBarForm = new ProgressBarForm(ParentForm);
            progressBarForm.TopMost = true;
            progressBarForm.MaxRange = this.MaxRange;
            progressBarForm.MinRange = this.MinRange;
            progressBarForm.StepValue = this.StepValue;
            progressBarForm.Position = this.Position;
            if (trackCancel != null)
                progressBarForm.TrackCancel = this.TrackCancel;
            if (!cancellationTokenSource.IsCancellationRequested)//此處的取消方法不是強制取消,CLR線程管理會在響應後合適的時候取消
            {                                                     //這種線程取消的方式,一個目的是爲了解決.NET4.0以前線程強制關閉的異常問題
                if (progressBarForm.ShowDialog() == DialogResult.OK)
                {
                    
                }
            }
        }

        public void Show()
        {
            ShowDialog();
        }

        public void ShowDialog()
        {
            try
            {
                cancellationTokenSource = new CancellationTokenSource();
                task = new Task(InitDialog, cancellationTokenSource.Token);
                task.Start();
                //此處創建的延續任務,爲確保線程取消的時候,出現異常情況(如:進度UI還沒有展示,主方法就已經走完)的保險處理
                Task cancelTask = task.ContinueWith(
                    (cancellatinTask) =>
                    {
                        if (progressBarForm != null && progressBarForm.Visible)
                            progressBarForm.Hide();
                    }, TaskContinuationOptions.OnlyOnCanceled);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public void HideDialog()
        {
            try
            {
                if (progressBarForm == null)//當進度窗體還沒有顯示出來,進度線程監視的方法已經走完,取消task線程
                    cancellationTokenSource.Cancel();
                else
                {
                    MethodInvoker invoker = () =>
                        {
                            if (progressBarForm.Visible)
                                progressBarForm.Hide();
                        };
                    if (progressBarForm.InvokeRequired)
                    {
                        progressBarForm.Invoke(invoker);
                    }
                    else
                    {
                        invoker();
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        public void Hide()
        {
            HideDialog();
        }

        public void Step()
        {
            if (progressBarForm != null)
                progressBarForm.Step();
        }
    }

       實現進度展示的UI類(ProgressBarForm)如下:

public partial class ProgressBarForm : Form
    {
        public ProgressBarForm(Form parent)
        {
            InitializeComponent();
            InitLocation(parent);
        }

        private void InitLocation(Form parent)
        {
            if (parent != null)
            {
                Left = parent.Left + (parent.Width - Width) / 2;
                Top = parent.Top + (parent.Height - Height) / 2;
            }
        }

        private int maxRange;
        private int minRange;
        private int stepValue;
        private int position;
        private string message;

        public ITrackCancel TrackCancel { get; set; }

        public string Message
        {
            get { return message; }
            set
            {
                if (message != value)
                {
                    MethodInvoker invoker = () => lab_Message.Text = value; ;
                    if (lab_Message.InvokeRequired)
                    {
                        //lab_Message.Invoke(invoker);
                        IAsyncResult asyncResult =lab_Message.BeginInvoke(invoker);
                        lab_Message.EndInvoke(asyncResult);
                    }
                    else
                    {
                        invoker();
                    }
                    message = value;
                }
            }
        }

        public int MaxRange
        {
            get { return maxRange; }
            set
            {
                if (maxRange != value)
                {
                    progressBar1.Maximum = value;
                    maxRange = value;
                }
            }
        }

        public int MinRange
        {
            get { return minRange; }
            set
            {
                if (minRange != value)
                {
                    progressBar1.Minimum = value;
                    minRange = value;
                }
            }
        }

        public int StepValue
        {
            get { return stepValue; }
            set
            {
                if (stepValue != value)
                {
                    progressBar1.Step = value;
                    stepValue = value;
                }
            }
        }

        public int Position
        {
            get { return position; }
            set
            {
                if (position != value)
                {
                    progressBar1.Value = value;
                    position = value;
                }
            }
        }

        public void Step()
        {
            MethodInvoker invoker = () =>
                {
                    int newValue = progressBar1.Value + this.StepValue;
                    //當進度超過最大值,默認賦最小值
                    if (newValue > this.MaxRange)
                    {
                        progressBar1.Value = MinRange;
                        progressBar1.Refresh();
                    }
                    else
                    {
                        progressBar1.Value = newValue;
                        progressBar1.Refresh();
                    }
                };
            if (progressBar1.InvokeRequired)
            {
                //progressBar1.Invoke(invoker);
                //採用異步委託的方法,提高進度條的響應速度,不知道線程創建多會不會影響效率(PS:沒有研究過異步委託創建線程的方式,不知道是從線程池那線程,還是每次來就創建一個)
                IAsyncResult asyncResult =progressBar1.BeginInvoke(invoker);
                progressBar1.EndInvoke(asyncResult);
            }
            else
            {
                invoker();
            }
        }

        private void ProgressBarForm_KeyDown(object sender, KeyEventArgs e)
        {
            if( e.KeyCode == Keys.Escape && TrackCancel.CancelOnKeyPress)
                TrackCancel.Cancel();
        }

        private void btn_Cancel_Click(object sender, EventArgs e)
        {
            if (TrackCancel.CancelOnClick)
            {
                TrackCancel.Cancel();
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            //當中斷處理不支持按鈕取消時候,將取消按鈕不顯示
            if (!TrackCancel.CancelOnClick)
            {
                this.Height = 65;
            }
        }
    }

         下面完成對進度的調用進度條的簡單封裝類(DialogManager)如下:

     /// <summary>
     /// 管理進度條的方法類
     /// </summary>
    public class ProgressManager
    {
        public static IStepProgress ShowProgressBarDialog(ITrackCancel trackCancel,Form pForm)
        {
            if (trackCancel == null)
                return null;
            return new ProgressBarDialog() {TrackCancel = trackCancel,ParentForm = pForm};
        }

        public static IStepProgress ShowProgressBarDialog(ITrackCancel trackCancel, Form pForm,int maxRange,int minRange,int stepValue)
        {
            if (trackCancel == null)
                return null;
            return new ProgressBarDialog()
                {
                    TrackCancel = trackCancel,
                    ParentForm = pForm,
                    MaxRange = maxRange,
                    MinRange = minRange,
                    StepValue = stepValue
                };
        }
    }

          最後,在自己代碼中調用進度的寫法如下:

         private void button1_Click(object sender, EventArgs e)
        {
            ITrackCancel trackCancel = new CancelTracker() {CancelOnClick = true, CancelOnKeyPress = true};
            IStepProgress stepProgress = ProgressManager.ShowProgressBarDialog(trackCancel,this);
            stepProgress.MinRange = 0;
            stepProgress.MaxRange = 100;
            stepProgress.StepValue = 1;
            bool pContinue = true;
            stepProgress.Show();
            for (int i = 0; i < 100; i++)
            {
                stepProgress.Message = String.Format("正在計算{0}...",i);
                pContinue = trackCancel.Continue();
                if(!pContinue)
                    break;
                stepProgress.Step();
                Thread.Sleep(50);
            }
            stepProgress.Hide();

        }

           以上爲對簡單進度條的封裝過程,接口的定義參考了ArcGIS的接口定義方式。如果想增加對其它的進度條的支持,需要實現對應的進度條接口和對應的展示UI即可。如:想增加一個轉圈等待的進度條展示進度,你只需要實現IProgressor接口,想支持中斷處理,實例化實現ITrackCancel接口的類即可,可以用工廠模式來管理你的進度條展示。

         題外的話:最近在學習fyiReporting和SharpDeveloper的源代碼,fyiReporting的源代碼太多,網上沒發現什麼知道的資源,看起來還是一知半解。SharpDeveloper的源碼,網上資源大都講的都是關於插件框架的東西,還有SharpDeveloper的團隊也出過一本書的,講的都是很久以前的版本。在此,求園友們對此感興趣的能指導下學習fyiReporting或者SharpDeveloper的資料,或者一起共同學習。

        本文的Demo:下載地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章