How to change the color of progressbar in C# .NET 3.5?

I'd like to do two things on my progress bar.

  1. Change the green colour to red.
  2. Remove the blocks and make it in one color.

Any information about those two things I wonder how to accomplish will be greatfuly appreaciated!

Thanks.


Solution 1:

OK, it took me a while to read all the answers and links. Here's what I got out of them:

Sample Results

The accepted answer disables visual styles, it does allow you to set the color to anything you want, but the result looks plain:

enter image description here

Using the following method, you can get something like this instead:

enter image description here

How To

First, include this if you haven't: using System.Runtime.InteropServices;

Second, you can either create this new class, or put its code into an existing static non-generic class:

public static class ModifyProgressBarColor
{
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
    static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr w, IntPtr l);
    public static void SetState(this ProgressBar pBar, int state)
    {
        SendMessage(pBar.Handle, 1040, (IntPtr)state, IntPtr.Zero);
    }
}

Now, to use it, simply call:

progressBar1.SetState(2);

Note the second parameter in SetState, 1 = normal (green); 2 = error (red); 3 = warning (yellow).

Hope it helps!

Solution 2:

Since the previous answers don't appear to work in with Visual Styles. You'll probably need to create your own class or extend the progress bar:

public class NewProgressBar : ProgressBar
{
    public NewProgressBar()
    {
        this.SetStyle(ControlStyles.UserPaint, true);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        Rectangle rec = e.ClipRectangle;

        rec.Width = (int)(rec.Width * ((double)Value / Maximum)) - 4;
        if(ProgressBarRenderer.IsSupported)
           ProgressBarRenderer.DrawHorizontalBar(e.Graphics, e.ClipRectangle);
        rec.Height = rec.Height - 4;
        e.Graphics.FillRectangle(Brushes.Red, 2, 2, rec.Width, rec.Height);
    }
}

EDIT: Updated code to make the progress bar use the visual style for the background

Solution 3:

This is a flicker-free version of the most accepted code that you can find as answers to this question. All credit to the posters of those fatastic answers. Thanks Dusty, Chris, Matt, and Josh!

Like "Fueled"'s request in one of the comments, I also needed a version that behaved a bit more... professionaly. This code maintains styles as in previous code, but adds an offscreen image render and graphics buffering (and disposes the graphics object properly).

Result: all the good, and no flicker. :)

public class NewProgressBar : ProgressBar
{
    public NewProgressBar()
    {
        this.SetStyle(ControlStyles.UserPaint, true);
    }

    protected override void OnPaintBackground(PaintEventArgs pevent)
    {
        // None... Helps control the flicker.
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        const int inset = 2; // A single inset value to control teh sizing of the inner rect.

        using (Image offscreenImage = new Bitmap(this.Width, this.Height))
        {
            using (Graphics offscreen = Graphics.FromImage(offscreenImage))
            {
                Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);

                if (ProgressBarRenderer.IsSupported)
                    ProgressBarRenderer.DrawHorizontalBar(offscreen, rect);

                rect.Inflate(new Size(-inset, -inset)); // Deflate inner rect.
                rect.Width = (int)(rect.Width * ((double)this.Value / this.Maximum));
                if (rect.Width == 0) rect.Width = 1; // Can't draw rec with width of 0.

                LinearGradientBrush brush = new LinearGradientBrush(rect, this.BackColor, this.ForeColor, LinearGradientMode.Vertical);
                offscreen.FillRectangle(brush, inset, inset, rect.Width, rect.Height);

                e.Graphics.DrawImage(offscreenImage, 0, 0);
            }
        }
    }
}

Solution 4:

In the designer, you just need to set the ForeColor property to whatever color you'd like. In the case of Red, there's a predefined color for it.

To do it in code (C#) do this:

pgs.ForeColor = Color.Red;

Edit: Oh yeah, also set the Style to continuous. In code, like this:

pgs.Style = System.Windows.Forms.ProgressBarStyle.Continuous;

Another Edit: You'll also need to remove the line that reads Application.EnableVisualStyles() from your Program.cs (or similar). If you can't do this because you want the rest of the application to have visual styles, then I'd suggest painting the control yourself or moving on to WPF since this kind of thing is easy with WPF. You can find a tutorial on owner drawing a progress bar on codeplex

Solution 5:

Using Matt Blaine and Chris Persichetti's answers I've created a progress bar that looks a bit nicer while allowing infinite color choice (basically I changed one line in Matt's solution):

ProgressBarEx:

using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace QuantumConcepts.Common.Forms.UI.Controls
{
    public class ProgressBarEx : ProgressBar
    {
        public ProgressBarEx()
        {
            this.SetStyle(ControlStyles.UserPaint, true);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            LinearGradientBrush brush = null;
            Rectangle rec = new Rectangle(0, 0, this.Width, this.Height);
            double scaleFactor = (((double)Value - (double)Minimum) / ((double)Maximum - (double)Minimum));

            if (ProgressBarRenderer.IsSupported)
                ProgressBarRenderer.DrawHorizontalBar(e.Graphics, rec);

            rec.Width = (int)((rec.Width * scaleFactor) - 4);
            rec.Height -= 4;
            brush = new LinearGradientBrush(rec, this.ForeColor, this.BackColor, LinearGradientMode.Vertical);
            e.Graphics.FillRectangle(brush, 2, 2, rec.Width, rec.Height);
        }
    }
}

Usage:

progressBar.ForeColor = Color.FromArgb(255, 0, 0);
progressBar.BackColor = Color.FromArgb(150, 0, 0);

Results

You can use any gradient you like!

Download

https://skydrive.live.com/?cid=0EDE5D21BDC5F270&id=EDE5D21BDC5F270%21160&sc=documents#