WinForms ProgressBar 控件全面教程
ProgressBar 是 WinForms 中用于可视化展示任务进度的核心控件,支持水平/垂直进度条、样式定制、多线程安全更新等特性。本教程将系统讲解其核心用法与高级技巧,结合实际案例帮助开发者快速掌握。
直接使用
progressBar1.Value = 0; //清空进度条
progressBar1.Maximum = 100; // 设置进度条的范围最大值
for (int i = 0; i < 100; i++)
{
progressBar1.Value += 1;
Thread.Sleep(50);
}
多线程
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
namespace WinForm之ProgressBar
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// 初始化进度条
progressBar1.Minimum = 0;
progressBar1.Maximum = 100;
progressBar1.Value = 0;
}
/// <summary>
/// 多线程工作
/// </summary>
private void DoWork()
{
// 模拟工作
for (int i = 0; i <= 100; i++)
{
// 更新进度
UpdateProgress(i);
// 模拟工作耗时
Thread.Sleep(50);
}
// 工作完成后可以显示完成消息
UpdateProgressComplete();
}
/// <summary>
/// 更新进度条
/// </summary>
/// <param name="value"></param>
private void UpdateProgress(int value)
{
if (progressBar1.InvokeRequired)
{
progressBar1.BeginInvoke(new Action<int>(UpdateProgress), value);
}
else
{
progressBar1.Value = value;
}
}
/// <summary>
/// 工作完成
/// </summary>
private void UpdateProgressComplete()
{
if (progressBar1.InvokeRequired)
{
progressBar1.BeginInvoke(new Action(UpdateProgressComplete));
}
else
{
MessageBox.Show("工作完成!");
}
}
private void button1_Click(object sender, EventArgs e)
{
// 启动后台线程
Thread workerThread = new Thread(DoWork);
workerThread.Start();
}
}
}
一、基础功能详解
1. 基本属性配置
// 初始化进度条
progressBar1.Minimum = 0; // 最小值(默认0)
progressBar1.Maximum = 100; // 最大值(默认100)
progressBar1.Value = 0; // 当前进度
progressBar1.Step = 10; // 每次调用PerformStep的增量
// 样式设置
progressBar1.Style = ProgressBarStyle.Blocks; // 块状样式(默认)
// 或 progressBar1.Style = ProgressBarStyle.Continuous; // 平滑样式
// 或 progressBar1.Style = ProgressBarStyle.Marquee; // 滚动条样式(不确定时长时使用)
2. 核心方法
Increment(int value)
:按指定值增加进度PerformStep()
:按Step
属性值增加进度MarqueeAnimationSpeed
:滚动条速度(仅限Marquee
样式)
// 示例:分步更新进度
private void StartTask() {
for (int i = 0; i <= 100; i += 10) {
progressBar1.PerformStep(); // 每次增加10(需提前设置Step=10)
// 或 progressBar1.Value = i;
Thread.Sleep(200); // 模拟耗时操作
}
}
二、高级功能实现
1. 多线程安全更新
问题:跨线程直接操作 UI 控件会抛出异常
解决方案:使用 Invoke
或 BackgroundWorker
// 方法1:使用Control.Invoke
private void UpdateProgress(int value) {
if (progressBar1.InvokeRequired) {
progressBar1.Invoke(new Action<int>(UpdateProgress), value);
} else {
progressBar1.Value = value;
lblStatus.Text = $"进度: {value}%";
}
}
// 方法2:使用BackgroundWorker(推荐)
private void btnStart_Click(object sender, EventArgs e) {
BackgroundWorker worker = new BackgroundWorker { WorkerReportsProgress = true };
worker.DoWork += (s, e) => {
for (int i = 0; i <= 100; i++) {
Thread.Sleep(50); // 模拟耗时任务
worker.ReportProgress(i);
}
};
worker.ProgressChanged += (s, e) => {
progressBar1.Value = e.ProgressPercentage;
lblStatus.Text = $"处理中... {e.ProgressPercentage}%";
};
worker.RunWorkerCompleted += (s, e) => {
MessageBox.Show("任务完成!");
};
worker.RunWorkerAsync();
}
2. 不确定时长任务(Marquee 模式)
// 适用于无法预估完成时间的任务(如文件复制、网络请求)
progressBar1.Style = ProgressBarStyle.Marquee;
progressBar1.MarqueeAnimationSpeed = 30; // 滚动速度(0-100)
// 当任务完成时切换回正常模式
private void TaskCompleted() {
progressBar1.Style = ProgressBarStyle.Blocks;
progressBar1.Value = progressBar1.Maximum; // 显示100%
}
3. 自定义颜色与样式
方法1:通过P/Invoke修改(需引用System.Runtime.InteropServices)
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
private const uint PBM_SETBARCOLOR = 0x0409; // 设置进度条颜色
private const uint PBM_SETBKCOLOR = 0x0201; // 设置背景色
private void SetProgressBarColor(ProgressBar progressBar, Color barColor, Color bgColor) {
SendMessage(progressBar.Handle, PBM_SETBARCOLOR, 0, ColorTranslator.ToWin32(barColor));
SendMessage(progressBar.Handle, PBM_SETBKCOLOR, 0, ColorTranslator.ToWin32(bgColor));
}
// 使用示例
SetProgressBarColor(progressBar1, Color.FromArgb(65, 184, 131), Color.WhiteSmoke);
方法2:自定义绘制(需继承控件)
public class CustomProgressBar : ProgressBar {
protected override void OnPaint(PaintEventArgs e) {
Rectangle rect = ClientRectangle;
Graphics g = e.Graphics;
// 绘制背景
using (SolidBrush brush = new SolidBrush(BackColor)) {
g.FillRectangle(brush, rect);
}
// 绘制进度
rect.Inflate(-3, -3); // 边框留白
if (Value > 0) {
Rectangle clip = new Rectangle(rect.X, rect.Y, (int)(rect.Width * ((double)Value / Maximum)), rect.Height);
using (SolidBrush brush = new SolidBrush(Color.FromArgb(65, 184, 131))) {
g.FillRectangle(brush, clip);
}
}
// 绘制文本(可选)
string text = $"{Value}%";
using (Font font = new Font("Arial", 8)) {
SizeF textSize = g.MeasureString(text, font);
PointF location = new PointF(
rect.X + (rect.Width - textSize.Width) / 2,
rect.Y + (rect.Height - textSize.Height) / 2);
using (SolidBrush brush = new SolidBrush(ForeColor)) {
g.DrawString(text, font, brush, location);
}
}
}
}
三、实用场景案例
1. 文件复制进度监控
private void CopyFilesWithProgress(string sourceDir, string destDir) {
string[] files = Directory.GetFiles(sourceDir);
int totalFiles = files.Length;
int copiedFiles = 0;
BackgroundWorker worker = new BackgroundWorker { WorkerReportsProgress = true };
worker.DoWork += (s, e) => {
foreach (string file in files) {
string destFile = Path.Combine(destDir, Path.GetFileName(file));
File.Copy(file, destFile, true);
copiedFiles++;
int progress = (int)((double)copiedFiles / totalFiles * 100);
worker.ReportProgress(progress);
}
};
worker.ProgressChanged += (s, e) => {
progressBar1.Value = e.ProgressPercentage;
lblStatus.Text = $"已复制 {copiedFiles}/{totalFiles} 个文件";
};
worker.RunWorkerCompleted += (s, e) => {
MessageBox.Show("文件复制完成!");
};
worker.RunWorkerAsync();
}
2. 多步骤任务进度展示
private void ExecuteMultiStepTask() {
int totalSteps = 3; // 假设有3个步骤
int currentStep = 0;
BackgroundWorker worker = new BackgroundWorker { WorkerReportsProgress = true };
worker.DoWork += (s, e) => {
// 步骤1:初始化
currentStep++;
worker.ReportProgress((int)((double)currentStep / totalSteps * 100), "初始化...");
Thread.Sleep(1000);
// 步骤2:数据处理
currentStep++;
worker.ReportProgress((int)((double)currentStep / totalSteps * 100), "数据处理中...");
Thread.Sleep(2000);
// 步骤3:生成报告
currentStep++;
worker.ReportProgress((int)((double)currentStep / totalSteps * 100), "生成报告...");
Thread.Sleep(1500);
};
worker.ProgressChanged += (s, e) => {
progressBar1.Value = e.ProgressPercentage;
lblStatus.Text = e.UserState?.ToString() ?? "";
};
worker.RunWorkerAsync();
}
3. 动态调整进度条范围
private void DynamicRangeTask() {
int currentValue = 0;
int stage = 1;
BackgroundWorker worker = new BackgroundWorker { WorkerReportsProgress = true };
worker.DoWork += (s, e) => {
// 第一阶段:0-50
progressBar1.Invoke(new Action(() => {
progressBar1.Minimum = 0;
progressBar1.Maximum = 50;
}));
while (currentValue < 50) {
currentValue += 5;
worker.ReportProgress(currentValue, $"阶段1: {currentValue}%");
Thread.Sleep(300);
}
// 第二阶段:50-100
stage = 2;
progressBar1.Invoke(new Action(() => {
progressBar1.Minimum = 50;
progressBar1.Maximum = 100;
currentValue = 50; // 重置当前值
}));
while (currentValue < 100) {
currentValue += 5;
worker.ReportProgress(currentValue, $"阶段2: {currentValue - 50}%");
Thread.Sleep(300);
}
};
worker.ProgressChanged += (s, e) => {
progressBar1.Value = e.ProgressPercentage;
lblStatus.Text = e.UserState?.ToString() ?? "";
};
worker.RunWorkerAsync();
}
四、性能优化建议
-
避免频繁更新:
- 进度变化小于5%时可不更新UI(通过阈值判断)
- 使用
Stopwatch
控制更新频率(如每200ms更新一次)
-
资源释放:
- 长时间运行的任务完成后,确保释放
BackgroundWorker
资源 - 取消任务时调用
worker.CancelAsync()
- 长时间运行的任务完成后,确保释放
-
异常处理:
worker.DoWork += (s, e) => { try { // 任务代码 } catch (Exception ex) { e.Result = ex; // 传递异常信息 } }; worker.RunWorkerCompleted += (s, e) => { if (e.Error != null) { MessageBox.Show($"任务失败: {e.Error.Message}"); } };
五、常见问题解决方案
-
进度条不更新:
- 检查是否在UI线程更新控件
- 确保
Maximum
>Minimum
且Value
在范围内
-
Marquee 模式不滚动:
- 确认未设置
Value
属性(会覆盖 Marquee 效果) - 检查
MarqueeAnimationSpeed
是否为0
- 确认未设置
-
自定义样式失效:
- P/Invoke 方法在64位系统可能需要额外处理
- 自定义绘制需设置
DoubleBuffered = true
减少闪烁
-
跨线程访问异常:
- 始终使用
Invoke
或BeginInvoke
更新UI - 避免在
DoWork
事件中直接操作控件
- 始终使用
六、扩展功能
1. 垂直进度条
通过自定义绘制实现:
public class VerticalProgressBar : ProgressBar {
protected override CreateParams CreateParams {
get {
CreateParams cp = base.CreateParams;
cp.Style |= 0x04; // PBS_VERTICAL 样式
return cp;
}
}
protected override void OnPaint(PaintEventArgs e) {
// 自定义绘制逻辑(需调整坐标系)
// 或使用P/Invoke设置垂直样式
}
}
2. 分段颜色进度条
public class SegmentedProgressBar : ProgressBar {
private List<Color> segments = new List<Color>();
public void AddSegment(Color color, double percentage) {
segments.Add(new Segment { Color = color, Percentage = percentage });
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
if (segments.Count == 0) return;
Rectangle rect = ClientRectangle;
rect.Inflate(-3, -3);
double lastEnd = 0;
foreach (var segment in segments) {
double start = lastEnd;
double end = start + segment.Percentage;
lastEnd = end;
if (end <= 0 || start >= 1) continue;
int startX = rect.X + (int)(rect.Width * Math.Max(0, start));
int endX = rect.X + (int)(rect.Width * Math.Min(1, end));
int width = endX - startX;
if (width > 0) {
using (SolidBrush brush = new SolidBrush(segment.Color)) {
e.Graphics.FillRectangle(brush, startX, rect.Y, width, rect.Height);
}
}
}
}
private class Segment {
public Color Color { get; set; }
public double Percentage { get; set; } // 0-1之间的比例
}
}
总结
ProgressBar 是 WinForms 中提升用户体验的关键控件,通过合理使用其基础功能与高级特性,可以:
- 明确展示任务进度:减少用户等待焦虑
- 支持多线程安全更新:避免UI冻结
- 灵活适配不同场景:从简单进度到复杂多阶段任务
- 实现个性化设计:通过颜色、样式定制增强视觉效果
开发者需注意:
- 始终在UI线程更新控件
- 合理设计进度反馈粒度
- 对长时间任务提供取消机制
- 考虑无障碍访问需求(如屏幕阅读器支持)
掌握 ProgressBar 的高级用法,可以显著提升 WinForms 应用的交互专业度。