Vasyl Boroviak
Vasyl Boroviak

Reputation: 6128

Disable WinForms ProgressBar animation

Is there a possbility to disable animation of the progress bar?

I need it for some pocess which is paused and not running at the moment. An average user would think the process is running if the progress bar is being blinking.

The advice to create own progress bar control is not what I'm looking for.

Upvotes: 13

Views: 22036

Answers (7)

Søren L. Fog
Søren L. Fog

Reputation: 11

I am also a little annoyed with the animation in the progress fillers, and the property for setting the animation speed to 0 (zero) didn't have any effect on a WinForms in dot net 8. So I found this post.

The first solution is elegant, but didn't work for me. I assume the post, being from 2010, is way too old and WM_ThisOrThat may have changed values in the meantime... Cannot rely on constant values! I could probably look them up in the Windows SDK, but who knows when they will change again.

So I took a look at the other suggestions (1, 2). And yes, both work, with some tweaks. Here's my code, inspired from the other answers, and it works like a charm.

Tweak the brushes and pens as you wish to make your own flavor.

public class MyProgressBar : ProgressBar
{
  private SolidBrush _brush = new(SystemColors.ControlDark);
  private SolidBrush _bkgr = new(SystemColors.Control);
  private Pen _border = new(SystemColors.ControlDarkDark, 2);
  public MyProgressBar()
  {
    // Setting these styles does the trick of sending paint message to OnPaint().
    // I did not spend any time understanding the details of why :-)
    SetStyle(ControlStyles.AllPaintingInWmPaint |
             ControlStyles.UserPaint |
             ControlStyles.OptimizedDoubleBuffer |
             ControlStyles.ResizeRedraw,
             true);
  }
  protected override void OnPaint(PaintEventArgs e)
  {
    // base.OnPaint(e);    // Don't call base class.

    // Make sure to use a float. In my case I needed to show a
    // percentage, which didn't work using the second downvoted answer.
    float fillRatio = (float)Value / (float)Maximum;
    int fillTo = (int)((float)Width * fillRatio);

    e.Graphics.FillRectangle(_brush, 0, 0, fillTo, Height);
    e.Graphics.FillRectangle(_bkgr, fillTo, 0, Width, Height);
    e.Graphics.DrawRectangle(_border, 0, 0, Width, Height);
  }
  public new int Value
  {
    get {return base.Value;}
    set {base.Value = value; Invalidate();}    // Remember to invalidate.
  }
}

Upvotes: 1

psur
psur

Reputation: 4519

My workaround was to use a Panel Control instead of ProgressBar. I changed BackColor, BorderStyle (to Fixed3D) and I manipulate its Width to display needed level of progress. I assumed that 100% of progress is equal to Width of the Form.

Panel as a ProgressBar

Upvotes: 4

ad48
ad48

Reputation: 1

Paste this as to code. This will rewrite the progress bar, it's also customizable to color.

public class CProgressBar : ProgressBar
{

public Color MyColor {
    get { return _color; }
    set {
        _color = value;
        MyBrush = new SolidBrush(_color);
        Invalidate();
    }
}

private Color _color = Color.Green;

public CProgressBar()
{
    SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
}

public int Value {
    get { return _value; }
    set {
        _value = value;
        Invalidate();
    }
}

private int _value;

private SolidBrush MyBrush = new SolidBrush(_color);

protected override void OnPaint(PaintEventArgs e)
{
    e.Graphics.FillRectangle(MyBrush, new Rectangle(0, 0, Width * (_value / Maximum), Height));
}
}

Upvotes: -2

SLaks
SLaks

Reputation: 887469

You can use the Vista progress bar's paused state, like this:

// Assuming a Form1 with 3 ProgressBar controls
private void Form1_Load(object sender, EventArgs e)
{
  SendMessage(progressBar2.Handle,
    0x400 + 16, //WM_USER + PBM_SETSTATE
    0x0003, //PBST_PAUSED
    0);

  SendMessage(progressBar3.Handle,
    0x400 + 16, //WM_USER + PBM_SETSTATE
    0x0002, //PBST_ERROR
    0);
}

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern uint SendMessage(IntPtr hWnd,
  uint Msg,
  uint wParam,
  uint lParam);

Upvotes: 23

Auxiliary
Auxiliary

Reputation: 2757

You could override the OnPaint() of the progressbar. You don't actually need to rewrite the whole thing, you just have to inherit the progressbar and override OnPaint like this:

public class my_progress_bar : ProgressBar {
        public Brush brush;
        public my_progress_bar() {
            this.SetStyle(ControlStyles.UserPaint, true);
            brush = Brushes.ForestGreen;
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            //base.OnPaint(e);
            Rectangle rectangle = e.ClipRectangle;
            rectangle.Width = (int)(rectangle.Width * ((double)Value / Maximum)) - 4;
            ProgressBarRenderer.DrawHorizontalBar(e.Graphics, e.ClipRectangle);
            rectangle.Height = Height - 4;
            e.Graphics.FillRectangle(brush, 2, 2, rectangle.Width, rectangle.Height);
        }
    }

Upvotes: -1

Mitchel Sellers
Mitchel Sellers

Reputation: 63126

What you will want to do is set the style on this control specifically to override the theme changes. This article gives you a bit of information.

Upvotes: 0

Adam Robinson
Adam Robinson

Reputation: 185643

The standard means of communicating to a user that an action is either paused or can't be accurately measured is to use the marquee display style.

progressBar1.Style = ProgressBarStyle.Marquee;

This style ignores the Maximum and Value properties and displays a progress bar "segment" that continually moves across the progress bar and loops around (it doesn't fill the progress bar, it moves what looks like a section of the bar all the way across the control and around to the beginning again.)

Upvotes: 3

Related Questions