平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“基于C#实现方法平滑流畅的进度条ProgressBar”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际采用顺序,把思路、关键写法和容易踩坑的地方讲清楚,便于大家直接对照操作。
引言
- 结合项目来看,ProgressBar 是进度显示控件,核心作用是直观展示任务执行进度(如文件下载、数据处理、批量操作)。
- 实际处理时,C# WinForm 中的 ProgressBar 是工具箱原生控件,轻松易用,但是要做到平滑流畅控制,还有一些小技巧的,本文以最轻松方式介绍给大家。
一、拖入控件
从实现思路看,将工具栏中的ProgressBar,拖入到界面中。能够到界面中会出现新的控件,当然为了美观也能够拖到底部状态栏(statusStrip)中。

二、设置核心属性
结合项目来看,添加控件后能够在属性中看到各种属性(如下所示图),表中列举的是最核心的属性项目。

| 属性 | 作用 |
|---|---|
| Minimum | 最小值(默认 0) |
| Maximum | 最大值(默认 100) |
| Value | 当前进度值(必须在 Min~Max 之间) |
| Style | 样式:Blocks(块状)/Continuous(连续)/Marquee(跑马灯,未知进度) |
| Enabled | 是否启用/禁用控件(True/False) |
| Visible | 是否显示/隐藏控件(True/False) |

三、 选择样式和构建代码
- 实际处理时,ProgressBar最先需看的设置属性就是样式(Style),Blocks(块状)/Continuous(连续)/Marquee(跑马灯,未知进度)三种可选。
1、无法确认过程时长
- 在这个场景下,若我们的运行的过程的时间完全无法确认,不知道任务总时长,又或者是先摆上界面临时采用。那么能够先设置样式(Style)为Marquee,只要在开始和结束的时候分别控制Visible即可。
//状态枚举
public enum DEV_RUN_STATUS
{
Null,
Idle,
Starting,
Running,
Stoping,
}
RUNNING_STEP startRunningStep = RUNNING_STEP.Ready;//开始运行步骤变量,Ready
//初始化加载
private void Form_main_Load(object sender, EventArgs e)
{
progressBar.Style = ProgressBarStyle.Marquee;//指定样式
progressBar.MarqueeAnimationSpeed = 30; // 指定动画速度
}
private void btnControlStart_Click(object sender, EventArgs e)
{
if (startRunningStep == RUNNING_STEP.Ready)
{
//运行开始显示进度条
ProgressBar.Visbile = true;
}
else if (startRunningStep == RUNNING_STEP.Stoping)
{
//运行结束隐藏进度条
ProgressBar.Visbile = false;
}
}
2、能够拿到运行时长
- 从实现思路看,启动时,我们能够知道运行时间哪怕是不确定的,我们能够传递过来,入下面的时间就是timer_Finish.Interval。我们起一个任务,本质上也是启动了一个新的线程。
- 结合项目来看,启动后调用了函数DoRealProgress()异步处理,不影响主线程。
- 在这个场景下,refreshInterval 是检查的间隔时间,当前每100ms刷新一次,如果总时长10秒,能够刷新1000次,1秒也能10次。当然也能够自行修改自定义。
- 从实现思路看,percent 是当前的运行时间百分比,ProgressBar.Value是当前显示的百分比,也能够将百分比以文字显示出来。
///
///开始和结束
///
private void btnControlStart_Click(object sender, EventArgs e)
{
if (startRunningStep == RUNNING_STEP.Ready)
{
//运行开始显示进度条
ProgressBar.Visbile = true;
//启用百分比文字显示
toolStripStatusLabel_percentage.Visible = true;
// 启动后台进度条任务,时间作为输入参数
Task.Run(() => DoRealProgress(timer_Finish.Interval));
}
else if (startRunningStep == RUNNING_STEP.Stoping)
{
//运行结束隐藏进度条
ProgressBar.Visbile = false;
//关闭百分比显示
toolStripStatusLabel_percentage.Visible = false;
}
}
///
/// 按时间比例自动计算进度
///
private async void DoRealProgress(int totalMs)
{
//读取开始时间作为分母
DateTime startTime = DateTime.Now;
// 每100ms刷新一次,比较平滑流畅
int refreshInterval = 100;
while (isStartRunning)
{
// 计算已用时间
double elapsedMs = (DateTime.Now - startTime).TotalMilliseconds;
// 计算百分比(0~100)读取当前时间除以开始时间获取百分比
int percent = (int)(elapsedMs / totalMs * 100);
// 防止超过100
percent = Math.Min(percent, 100);
// 委托更新UI
this.Invoke(new Action(() => {
//设置百分比
ProgressBar.Value = percent;
//文本显示百分比
toolStripStatusLabel_percentage.Text = $"{percent}%";
}));
//延时
await Task.Delay(refreshInterval);
}
}
总结
- 在这个场景下,本文轻松介绍了ProgressBar的基础功能和采用,同时采用代码实现了平滑流畅的效果,很实用。已知进度和时间用 Value 控制,未知进度用 Marquee 跑马灯;
- 落到代码里,注意WinForm 跨线程更新 UI 用到了Task任务和UI执行this.Invoke()委托,将任务必须放在后台线程,避免界面卡死,也同时简化了异步代码,可读性更高;
- 直接复制代码即可运行,适配绝大多数进度场景哦!
落到代码里,总的来说,C#实现进度条ProgressBar适合结合实际项目边做边理解。先抓住核心思路,再逐步补上细节和边界处理,最后效果会更稳定,也更容易复用。
