ProgressBar is slow in Windows Forms

前端 未结 5 2155
不知归路
不知归路 2020-12-03 07:40

I\'m using Windows Vista and Visual Studio 2010. Create a .Net 4 Windows Forms Application. Drop a progress bar on the default form, add code to handle the form load event a

相关标签:
5条回答
  • 2020-12-03 08:19

    I liked Derek W's answer and I managed to find a solution which supports data binding. I inherited from System.Windows.Forms.ProgressBar and created new bindable property. Otherwise it's the same:

    [DefaultBindingProperty("ValueNoAnimation")]
    public class NoAnimationProgressBar : ProgressBar
    {
        /// <summary>
        /// Sets the progress bar value, without using 'Windows Aero' animation.
        /// This is to work around (hack) for a known WinForms issue where the progress bar 
        /// is slow to update. 
        /// </summary>
        public int ValueNoAnimation
        {
            get => Value;
            set
            {
                // To get around the progressive animation, we need to move the 
                // progress bar backwards.
                if (value != Maximum)
                    Value = value + 1; // Move past
                else
                {
                    // Special case as value can't be set greater than Maximum.
                    Maximum = value + 1;
                    Value = value + 1;
                    Maximum = value;
                }
    
                Value = value; // Move to correct value
            }
        }
    }
    

    You can bind to the property like this (viewModel has an int property called Value):

    var dataSource = new BindingSource { DataSource = _viewModel };
    progressBarBindingHack.DataBindings.Add("ValueNoAnimation", dataSource, "Value");
    
    0 讨论(0)
  • 2020-12-03 08:22

    This is just how the Vista/7 progress bar is designed. When you change the value of the progress bar, the bar is animated to that value progressively.

    The only way I know of avoiding this problem is to go backwards when updating the progress bar, as follows:

    progressBar1.Value = n;
    if (n>0)
        progressBar1.Value = n-1;
    

    For a more complete discussion see Disabling .NET progressbar animation when changing value?

    0 讨论(0)
  • 2020-12-03 08:27

    Building off of Heffernan's tip on going backwards with the progress bar and Reinhart's extension method approach in a related question, I came up with my own solution.

    The solution is pretty seamless and successfully handles the issue you will encounter when the value is at Maximum. This extension method to ProgressBar alleviates the lagging that is caused from the progressive animation style present in the WinForms ProgressBar control when running on Windows Vista and 7 (I haven't tested on Windows 8 yet).

    public static class ExtensionMethods
    {
        /// <summary>
        /// Sets the progress bar value, without using 'Windows Aero' animation.
        /// This is to work around a known WinForms issue where the progress bar 
        /// is slow to update. 
        /// </summary>
        public static void SetProgressNoAnimation(this ProgressBar pb, int value)
        {
            // To get around the progressive animation, we need to move the 
            // progress bar backwards.
            if (value == pb.Maximum)
            {
                // Special case as value can't be set greater than Maximum.
                pb.Maximum = value + 1;     // Temporarily Increase Maximum
                pb.Value = value + 1;       // Move past
                pb.Maximum = value;         // Reset maximum
            }
            else
            {
                pb.Value = value + 1;       // Move past
            }
            pb.Value = value;               // Move to correct value
        }
    }
    

    Sample usage:

    private void backgroundWorker_ProgressChanged(object sender, 
                                                      ProgressChangedEventArgs e)
    {
         progressBar.SetProgressNoAnimation(e.ProgressPercentage);
    }
    
    0 讨论(0)
  • 2020-12-03 08:30

    A much simpler answer, as shown here, is to do this:

    pbar.Value = value;
    pbar.Value = value - 1;
    pbar.Value = value;
    

    Explanation:

    It animates the PB as it increases, but not while it decreases. And that is why the above hack sppears to 'fix' the problem.

    0 讨论(0)
  • 2020-12-03 08:41

    You can easily write a custom progress bar to show its value without animation. The following is a simple implementation to show the progress from 0 to 100 and revert to 0.

    public class ProgressBarDirectRender : UserControl
    {
        private int _value;
        public int Value
        {
            get { return _value; }
            set
            {
                if (value < 0 || value > 100)
                    throw new ArgumentOutOfRangeException("value");
                _value = value;
                const int margin = 1;
                using (var g = CreateGraphics())
                {
                    if (_value == 0)
                        ProgressBarRenderer.DrawHorizontalBar(g, ClientRectangle);
                    else
                    {
                        var rectangle = new Rectangle(ClientRectangle.X + margin,
                                                      ClientRectangle.Y + margin,
                                                      ClientRectangle.Width * _value / 100 - margin * 2,
                                                      ClientRectangle.Height - margin * 2);
                        ProgressBarRenderer.DrawHorizontalChunks(g, rectangle);
                    }
                }
            }
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            ProgressBarRenderer.DrawHorizontalBar(e.Graphics, ClientRectangle);
        }
    }
    
    0 讨论(0)
提交回复
热议问题