C#Winform进度条的使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xiaojie119120/article/details/54581622

一个好的进度条能有效的改善用户体验。当然,前提是进度条做得好才行,做得差作用就正好相反了,可能造成程序假死、无法关闭等。

下面是一个真实例子,我自己写代码的经验(由于我使用进度条都是自己琢磨,所以和网上的例子不太一样)。

以下是我一年前写的进度条,当时刚学C#,所以写出的进度条窗体效果非常差,正好做一个反例。

        public int current = 0;//当前值
        public int max = 100;//最大值
        
        public ProgressForm()
        {

            InitializeComponent();

        }
        //循环跑进度条
        public void pand()
        {
            int i, old = 0;
            do
            {


                if (current != old)
                {
                    for (i = 0; i < 10; i++)
                    {
                        this.progressBar1.Value += 1;
                        this.progressBar1.Update();
                        Application.DoEvents();
                    }
                    old = current;
                }
                this.progressBar1.Update();
                Application.DoEvents();
                if (current == 0)
                {
                    this.label1.Text = "正在写入论文信息,请稍等...";
                }
                else
                {
                    this.label1.Text = "正在写入论文正文,请稍等...";
                }
            }
            while (current != max);
            while (this.progressBar1.Value != this.progressBar1.Maximum)
            {
                this.progressBar1.Value += 1;
                this.progressBar1.Update();
                Application.DoEvents();

            }
        }
        //窗体显示时的事件
        private void ProgressForm_Shown(object sender, EventArgs e)
        {
            this.progressBar1.Maximum = max * 10;
            this.progressBar1.Value = 0;
            pand();
            this.Close();
        }

好吧,代码非常繁琐,我稍微解释一下这段代码以及当时我的想法:

我定义了两个公共变量:max存后台需要完成任务任务数,current存当前完成了第几项任务。然后pand()方法负责循环检测current的值,然后给进度条增加值,当current等于max时停止循环关闭进度条窗体,代表任务完成。

                        while (this.progressBar1.Value != this.progressBar1.Maximum)
            {
                this.progressBar1.Value += 1;
                this.progressBar1.Update();
                Application.DoEvents();

            }

这段代码的作用是让进度条跑的时候不跳格,类似this.progressBar1.PerformStep();方法(当时我并不知道进度条有这个方法)。下面说一下这段代码存在的问题,首先使用无限循环会造成程序假死现象(就是跑进度的时候无法关闭进度条窗体),这非常影响用户体验,其次是代码繁琐,明明是非常简单的事,写得那么繁琐,既影响阅读又影响性能,最后是进度条的画面和Value不同步(即每次进度条的Value已经加完了,进度条还没跑完),导致用户看到的效果是进度还没跑完,进度条就关了。

下面看一下我修改后的进度条窗体代码:

        private int _current = 0;
        /// <summary>
        /// 当前值
        /// </summary>
        public int Current
        {
            get { return _current; }
            set
            {
                _current = value;
                AddValue();
            }
        }
        private int _max = 100;
        /// <summary>
        /// 最大值
        /// </summary>
        public int Max
        {
            get { return _max; }
            set 
            { 
                _max = value;
                this.progressBar1.Maximum = (_max - 1) * 10;
                this.progressBar1.Value = 0;
            }
        }
        MainForm father;
        public ProgressForm(MainForm main)
        {
            father = main;
            InitializeComponent();
            this.label1.Text = "正在写入论文信息,请稍等...";
        }

        /// <summary>
        /// 给进度条加值的方法
        /// </summary>
        private void AddValue()
        {
            if (_current > 0)
            {
                this.label1.Text = "正在写入论文正文,请稍等...";
            }
            this.progressBar1.PerformStep();
            if (this._current * 10 > this.progressBar1.Maximum)
            {
                this.DialogResult = System.Windows.Forms.DialogResult.OK;
                this.Close();

            }

        }
        /// <summary>
        /// 取消按钮的方法
        /// </summary>
        private void Cancel()
        {
            father.CreateThesisIsRuning = false;
            progressBar1.Style = ProgressBarStyle.Marquee;
            label1.Text = "取消中,请稍等...";
            while (true)
            {
                if (!father.CreateThesisTh.IsAlive)
                    break;
                Application.DoEvents();
            }
        }
        /// <summary>
        /// 取消按钮事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonX1_Click(object sender, EventArgs e)
        {
            Cancel();
        }

同样是需要当前值和最大值变量,不同的是我把这两个字段封装起来了,AddValue()方法负责给进度条增加值,Cancel()方法负责执行用户点击取消按钮的操作。

在设置Current值时执行AddValue()方法,AddValue()方法中使用了this.progressBar1.PerformStep(),这个方法的作用是按照设置好的this.progressBar1.Step值给进度条增加值,比如Step=10,调用这个方法就相当于给进度条添加10次值,每次增加1,就不会造成进度条跳跃格数过大,提升用户体验。

用户在点击取消按钮时,就设置后台进程CreateThesisIsRuning=false,使进程停止,由于进程正常可能停止需要一定的时间,所以用一个循环去检测CreateThesisTh.IsAlive的值判断进程是否结束,此时还要修改进度条类型为ProgressBarStyle.Marquee,Application.DoEvents()可以避免循环卡死。

然后针对进度不同步,在设置Max值得时候,this.progressBar1.Maximum = (_max - 1) * 10,将进度条的最大值设置成max最大值-10,然后最后判断进度条是否结束时使用this._current * 10 > this.progressBar1.Maximum去判断,这样就可以使进度条画面,原理是进度条画面更新比较慢,所以减小进度条的最大值,让进度条先跑完再执行完任务,造成进度条在等任务,虽然还是不同步,但是在用户体验上效果好多了。

下面看一下效果:

跑条中.png

图1 任务进行中

取消中.png

图2 任务取消中

以上是我自己想的一个进度条方案,如有雷同,纯属巧合,欢迎大家指正。

猜你喜欢

转载自blog.csdn.net/xiaojie119120/article/details/54581622