C#进度条实现

C#进度条实现

写在开头

记得本科大二时,和老师一起做项目,那时候刚接触编程没多久,技术很烂,当时有个功能是把shapfile文件中的属性表导出至本地Excel(*xls)格式,就想着能不能做个进度条,提高一下用户体验,于是乎,就兴奋的往窗口上拖个进度条(这个最擅长),然后各种捯饬,后来终于实现了,但是发现只有当表的记录较少时,进度条才能实时更新,否则记录很多时,进度条一直不更新,直至导出完成后进度条直接满血,当时很惆怅,百度了、谷歌了,得知这叫“UI阻塞”必须另开线程才能解决,这下我更惆怅了,那时的我“闻线程色变”,这种“黑技术”我做不到啊!!!

概述

  • 实现效果,点击按钮弹出进度条窗口,并开始执行任务,在进度条及文本标签中更新任务进度,关闭进度窗口时可终止任务
  • 实现技术,多线程(主线程更新UI,子线程处理耗时任务),委托

代码实现

  • 定义委托,限定进度回调函数接口
namespace Progress
{
    public delegate void SetProgressValueEventHandler(int pos);//设置进度值的委托 定义参数列表
}
  • MainFrm类:主界面,用于启动任务子线程,并开启进度窗口;
namespace Progress
{
    public partial class MainFrm : Form
    {
        public event SetProgressValueEventHandler SetProgressValueEvent;//定义事件用于回调
        public Thread ProcessThread //定义子线程用于处理耗时任务
        {
            get;
            set;
        }

        public MainFrm()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ProcessThread = new Thread(new ThreadStart(HandleThread));//子线程初始化
            ProgressFrm pFrm = new ProgressFrm(this);
            ProcessThread.Start();//开启线程        
            pFrm.Show();
        }

        private void HandleThread()//线程处理函数,实现耗时任务
        {
            Run run = new Run();
            run.RunProgress(150, SetProgressValueEvent);
        }
    }
}
  • Run类:耗时任务实现类,实现耗时任务的逻辑代码;
 class Run
 {
      public void RunProgress(int range, SetProgressValueEventHandler setProgressBar)
      {
         try
         {
             for (int i = 0; i < range; i++)
             {
                 Thread.Sleep(100);
                 //int p = 10 / (i - 10);//此处为了验证程序错误响应处理,当i=10时触发异常
                 setProgressBar(i * 100 / range);
             }
             setProgressBar(100);//耗时任务结束,进度条达到100;
         }
        catch (System.Exception ex)
        {
             System.Console.WriteLine(ex.Message);
             setProgressBar(101);//处理任务失败,向进度窗口传递消息传递值大于100或小于0的数
        }
     }
}
  • ProgressFrm类:进度控制窗口,用于显示进度。
namespace Progress
{
    public partial class ProgressFrm : Form
    {
        private MainFrm mFrm;
        public ProgressFrm(MainFrm mFrm)
        {
            InitializeComponent();
            this.mFrm = mFrm;
            //绑定事件处理函数
            mFrm.SetProgressValueEvent += new SetProgressValueEventHandler(OnProgressValueChanged);

        }
        private void OnProgressValueChanged(int pos)//事件处理函数,设置进度条和进度值
        {
            SetProgressBarValueInvoke(pos);
            SetProgressLabelValueInvoke(pos);
        }


        private void SetProgressBarValueInvoke(int pos)//跨线程调用
        {
            if (progressBar.InvokeRequired)
            {
                SetProgressValueEventHandler setProgress = new SetProgressValueEventHandler(SetProgressBarValue);
                progressBar.Invoke(setProgress, new object[] { pos });
            }
            else
            {
                SetProgressBarValue(pos);
            }
        }
       private void SetProgressBarValue(int pos)
        {
            //this.progressBar.Value = pos;
            if (pos <= progressBar.Maximum && pos >= 0)
            {
                this.progressBar.Value = pos;

            }
        }

        private void SetProgressLabelValueInvoke(int pos)//跨线程调用
        {
            if (label.InvokeRequired)
            {
                SetProgressValueEventHandler setProgressLabel = new SetProgressValueEventHandler(SetProgressLabelValue);
                progressBar.Invoke(setProgressLabel, new object[] { pos });
            }
            else
            {
                SetProgressBarLabelvalue(pos);
            }
        }
        private void SetProgressLabelValue(int pos)
        {
            if (pos <= progressBar.Maximum && pos >=0)
            {
                if (pos == progressBar.Maximum)
                {
                    MessageBox.Show("处理成功···", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    this.Close();
                } 
                else
                {
                    this.label.Text = pos.ToString() + "%";
                }
            }
            else
            {
                MessageBox.Show("处理失败···", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                this.Close();
            }

        }


        private void ProgressFrm_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                mFrm.SetProgressValueEvent -= new SetProgressValueEventHandler(OnProgressValueChanged);
                mFrm.ProcessThread.Abort();
            }
            catch (System.Exception ex)
            {

            }
        }
    }
}

总结

现在读研,项目需要C#不常用了,但我想说虽然C#的语法比C++要容易很多(这竟然成为很多人对C#口诛笔伐的缘由),之所以容易而是微软把太多东西封装了,语法虽易但其中确蕴含了更深刻的思想。

封装意味着抽象,意味着更多需要理解的哲学思想。——室友(姜哥)

对于我来说的便是委托/事件对C++函数指针的封装,研究了很久才算理解。

**能力有限请批评指正**

下载地址

C#进度条实现源码

你可能感兴趣的:(.Net)