C#
.NET 3.5
ProgressBar
UI Customization
Programming

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

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In WinForms on .NET 3.5, the built in ProgressBar is a wrapper over a native Windows control, and theme rendering decides most visual details. That is why changing ForeColor often has no visible effect. If you need reliable custom color, the practical approach is to draw your own control and keep progress updates thread safe.

Why the Default WinForms ProgressBar Ignores Color

The default control delegates painting to the operating system theme engine. In many environments this means BackColor and ForeColor are ignored for the fill area. You can still set value and style, but not arbitrary branding colors.

For teams with strict UI requirements, owner drawing is usually the only predictable solution. It also gives control over border, gradients, text overlays, and animation without depending on OS theme quirks.

Build a Colored Owner Drawn Progress Control

Create a small custom control that paints background, fill, and border. This example runs on .NET 3.5 WinForms.

csharp
1using System;
2using System.ComponentModel;
3using System.Drawing;
4using System.Windows.Forms;
5
6public class ColorProgressBar : Control
7{
8    private int minimum = 0;
9    private int maximum = 100;
10    private int progressValue = 0;
11
12    [DefaultValue(0)]
13    public int Minimum
14    {
15        get { return minimum; }
16        set
17        {
18            minimum = value;
19            if (maximum <= minimum) maximum = minimum + 1;
20            if (progressValue < minimum) progressValue = minimum;
21            Invalidate();
22        }
23    }
24
25    [DefaultValue(100)]
26    public int Maximum
27    {
28        get { return maximum; }
29        set
30        {
31            maximum = value;
32            if (maximum <= minimum) maximum = minimum + 1;
33            if (progressValue > maximum) progressValue = maximum;
34            Invalidate();
35        }
36    }
37
38    [DefaultValue(0)]
39    public int Value
40    {
41        get { return progressValue; }
42        set
43        {
44            progressValue = Math.Max(minimum, Math.Min(maximum, value));
45            Invalidate();
46        }
47    }
48
49    [DefaultValue(typeof(Color), "SteelBlue")]
50    public Color ProgressColor { get; set; }
51
52    [DefaultValue(typeof(Color), "Gainsboro")]
53    public Color TrackColor { get; set; }
54
55    public ColorProgressBar()
56    {
57        SetStyle(ControlStyles.AllPaintingInWmPaint |
58                 ControlStyles.OptimizedDoubleBuffer |
59                 ControlStyles.UserPaint, true);
60
61        ProgressColor = Color.SteelBlue;
62        TrackColor = Color.Gainsboro;
63        Size = new Size(280, 22);
64    }
65
66    protected override void OnPaint(PaintEventArgs e)
67    {
68        base.OnPaint(e);
69
70        e.Graphics.Clear(TrackColor);
71
72        float ratio = (float)(progressValue - minimum) / (maximum - minimum);
73        int fillWidth = (int)(ratio * Width);
74
75        using (SolidBrush fill = new SolidBrush(ProgressColor))
76        {
77            e.Graphics.FillRectangle(fill, 0, 0, fillWidth, Height);
78        }
79
80        ControlPaint.DrawBorder(e.Graphics, ClientRectangle, Color.Gray, ButtonBorderStyle.Solid);
81    }
82}

This gives full control over color while keeping behavior close to the standard progress bar.

Update Progress Safely from Background Work

Long operations should not block the UI thread. Use BackgroundWorker in .NET 3.5 and update the custom control in ProgressChanged.

csharp
1private void RunTask()
2{
3    ColorProgressBar bar = new ColorProgressBar();
4    bar.ProgressColor = Color.SeaGreen;
5    bar.Dock = DockStyle.Top;
6    this.Controls.Add(bar);
7
8    BackgroundWorker worker = new BackgroundWorker();
9    worker.WorkerReportsProgress = true;
10
11    worker.DoWork += delegate
12    {
13        for (int i = 0; i <= 100; i++)
14        {
15            System.Threading.Thread.Sleep(25);
16            worker.ReportProgress(i);
17        }
18    };
19
20    worker.ProgressChanged += delegate(object sender, ProgressChangedEventArgs e)
21    {
22        bar.Value = e.ProgressPercentage;
23    };
24
25    worker.RunWorkerAsync();
26}

This pattern avoids cross thread exceptions and keeps drawing smooth during frequent updates.

Consider a Native Message Shortcut and Its Limits

Some developers use SendMessage with progress state messages to switch between pre defined visual states. This can show alternative colors such as warning or error in some Windows versions. It is not fully customizable and depends on OS theme support, so it is not a substitute for owner drawing when branding is strict.

If your requirement is simply to show success versus warning, native state messages can be enough. If the requirement is exact brand palette control, use a custom control.

Common Pitfalls

  • Expecting the standard WinForms ProgressBar to obey ForeColor on all machines.
  • Updating UI controls directly from worker threads, which causes thread access exceptions.
  • Skipping double buffering in custom drawing, which creates visible flicker.
  • Forgetting bounds checks for min, max, and value, causing negative widths or incorrect fill ratios.
  • Redrawing too often during very small progress increments without throttling.

Summary

  • In .NET 3.5 WinForms, the default progress bar does not provide reliable arbitrary color control.
  • A custom owner drawn control is the most predictable solution for branded colors.
  • Use BackgroundWorker to keep the interface responsive while work is running.
  • Validate range logic and enable double buffering for smooth rendering.
  • Use native message based color states only for limited scenarios, not full customization.

Course illustration
Course illustration

All Rights Reserved.