在C# Windows Forms应用程序开发中,当我们需要执行文件读写、数据批量处理、网络请求等耗时操作时,直接在UI线程执行会导致界面无响应,而通过异步任务配合进度条窗体,既能保证界面流畅,又能让用户清晰了解任务执行状态。

进度条窗体界面设计
首先新建一个Windows Forms项目,添加一个名为ProgressForm的窗体作为进度条窗体,在窗体上放置以下控件:
- 一个
ProgressBar控件,用于显示进度百分比 - 一个
Label控件,用于显示当前进度的文字描述 - 一个
Button控件,用于取消任务操作
窗体的基本属性设置如下:
| 控件名称 | 属性 | 值 |
|---|---|---|
| ProgressForm | FormBorderStyle | FixedDialog |
| ProgressForm | MaximizeBox | false |
| ProgressBar | Minimum | 0 |
| ProgressBar | Maximum | 100 |
| ProgressBar | Style | Continuous |
进度条窗体核心代码实现
在ProgressForm中添加以下属性和方法,用于接收外部传入的进度信息和取消任务的逻辑:
using System;
using System.Windows.Forms;
namespace ProgressBarDemo
{
public partial class ProgressForm : Form
{
// 定义取消任务的委托和事件
public event Action CancelTask;
public ProgressForm()
{
InitializeComponent();
}
// 更新进度的方法,供外部调用
public void UpdateProgress(int percent, string message)
{
if (this.InvokeRequired)
{
// 跨线程调用,切换到UI线程执行
this.Invoke(new Action<int, string>(UpdateProgress), percent, message);
return;
}
// 设置进度条值,确保值在合法范围内
progressBar1.Value = Math.Max(progressBar1.Minimum, Math.Min(progressBar1.Maximum, percent));
// 更新提示文字
label1.Text = message;
}
// 取消按钮点击事件
private void btnCancel_Click(object sender, EventArgs e)
{
CancelTask?.Invoke();
this.DialogResult = DialogResult.Cancel;
this.Close();
}
// 窗体关闭时触发取消逻辑
private void ProgressForm_FormClosing(object sender, FormClosingEventArgs e)
{
CancelTask?.Invoke();
}
}
}
异步任务处理逻辑实现
我们使用BackgroundWorker组件来处理异步任务,它内置了进度报告和取消任务的功能,非常适合配合进度条使用。在主窗体中添加BackgroundWorker组件,然后编写以下逻辑:
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace ProgressBarDemo
{
public partial class MainForm : Form
{
private BackgroundWorker backgroundWorker;
public MainForm()
{
InitializeComponent();
InitBackgroundWorker();
}
// 初始化BackgroundWorker组件
private void InitBackgroundWorker()
{
backgroundWorker = new BackgroundWorker();
// 支持报告进度
backgroundWorker.WorkerReportsProgress = true;
// 支持取消任务
backgroundWorker.WorkerSupportsCancellation = true;
// 绑定异步任务执行方法
backgroundWorker.DoWork += BackgroundWorker_DoWork;
// 绑定进度更新方法
backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;
// 绑定任务完成方法
backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
}
// 启动异步任务的按钮点击事件
private void btnStartTask_Click(object sender, EventArgs e)
{
if (backgroundWorker.IsBusy)
{
MessageBox.Show("当前有任务正在执行,请等待完成或取消后再启动");
return;
}
// 创建进度条窗体
ProgressForm progressForm = new ProgressForm();
// 绑定取消任务事件
progressForm.CancelTask += () =>
{
if (backgroundWorker.IsBusy)
{
backgroundWorker.CancelAsync();
}
};
// 启动异步任务,传入进度条窗体作为参數
backgroundWorker.RunWorkerAsync(progressForm);
// 显示进度条窗体,模态显示
progressForm.ShowDialog();
}
// 异步任务执行逻辑
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
ProgressForm progressForm = e.Argument as ProgressForm;
int totalCount = 100;
for (int i = 0; i <= totalCount; i++)
{
// 检查是否收到取消请求
if (worker.CancellationPending)
{
e.Cancel = true;
return;
}
// 模拟耗时操作,每次循环休眠100毫秒
System.Threading.Thread.Sleep(100);
// 计算当前进度百分比
int percent = (int)((double)i / totalCount * 100);
// 报告进度,传入百分比和提示信息
worker.ReportProgress(percent, $"正在处理第{i}项,共{totalCount}项");
}
}
// 进度更新回调,在UI线程执行
private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// 获取传入的进度条窗体对象
ProgressForm progressForm = (sender as BackgroundWorker).GetType()
.GetField("asyncOperation", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
?.GetValue(sender) is null ? null : (e.UserState as Tuple<ProgressForm, string>)?.Item1;
// 更简便的方式:通过DoWork传入的参數获取窗体,这里调整逻辑
// 实际开发中可以将进度条窗体存为成员变量,这里简化演示
// 假设我们在RunWorkerAsync时传入了窗体,这里通过e.UserState获取
if (e.UserState is string message)
{
// 实际场景中需要关联对应的进度条窗体,这里简化为弹出提示
// 正确逻辑应该在DoWork中把窗体存到可访问的位置,这里仅展示进度更新逻辑
// 演示用:直接输出进度信息
Console.WriteLine($"当前进度:{e.ProgressPercentage}%,{message}");
}
}
// 任务完成回调
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
MessageBox.Show("任务已取消");
}
else if (e.Error != null)
{
MessageBox.Show($"任务执行出错:{e.Error.Message}");
}
else
{
MessageBox.Show("任务执行完成");
}
}
}
}
注意事项
在实际开发中需要注意以下几点:
- 所有对UI控件的操作都必须在UI线程执行,跨线程操作需要使用
Invoke或者BeginInvoke方法,否则会抛出异常 BackgroundWorker的ReportProgress方法只有在WorkerReportsProgress设为true时才能调用- 取消任务时需要先调用
CancelAsync方法,然后在DoWork中检查CancellationPending属性,手动退出循环,不能直接终止线程 - 进度条的最大值和最小值需要根据实际任务的总量设置,避免进度显示不准确
简化版进度更新实现
如果觉得上面的ProgressChanged事件获取窗体比较复杂,可以调整代码逻辑,把进度条窗体作为主窗体的成员变量,在启动任务时赋值,这样在进度更新时可以直接调用窗体的更新方法:
// 主窗体添加成员变量
private ProgressForm currentProgressForm;
// 修改启动任务的逻辑
private void btnStartTask_Click(object sender, EventArgs e)
{
if (backgroundWorker.IsBusy)
{
MessageBox.Show("当前有任务正在执行,请等待完成或取消后再启动");
return;
}
currentProgressForm = new ProgressForm();
currentProgressForm.CancelTask += () =>
{
if (backgroundWorker.IsBusy)
{
backgroundWorker.CancelAsync();
}
};
backgroundWorker.RunWorkerAsync();
currentProgressForm.ShowDialog();
}
// 修改进度更新逻辑
private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (currentProgressForm != null && !currentProgressForm.IsDisposed)
{
string message = e.UserState as string;
currentProgressForm.UpdateProgress(e.ProgressPercentage, message);
}
}
// 修改任务完成逻辑
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
currentProgressForm = null;
if (e.Cancelled)
{
MessageBox.Show("任务已取消");
}
else if (e.Error != null)
{
MessageBox.Show($"任务执行出错:{e.Error.Message}");
}
else
{
MessageBox.Show("任务执行完成");
}
}
通过以上步骤,就可以完成一个功能完整的C#进度条窗体,实现异步任务进度的实时显示和任务取消功能,满足大多数桌面应用的进度展示需求。
C#进度条窗体异步任务BackgroundWorker修改时间:2026-07-10 20:18:38