如何在C#中实现反映真实加载进度的进度条?
实现真实加载进度的Progress Bar(C# WinForms)
要实现像GTA离线模式那样的真实进度条,核心是让进度条的推进完全依赖实际加载任务的完成情况,而不是用定时器模拟。下面是具体的实现步骤和代码:
核心思路
- 拆分所有需要加载的资产/任务(比如配置文件、纹理、数据库数据、初始化操作等)
- 跟踪每个任务的完成状态,计算已完成任务占总任务的比例(或已加载字节占总字节的比例)
- 每个任务完成后,在UI线程安全地更新进度条
替换假进度条的完整实现
1. 定义进度跟踪变量
// 总加载任务数(根据你的实际需求调整) private int _totalLoadingTasks = 4; // 已完成的任务数 private int _completedTasks = 0;
2. 异步加载主流程
把原来的定时器逻辑替换成真实的异步加载流程:
private async void loadingForm_Load(object sender, EventArgs e) { // 启动异步加载,避免卡死UI await ExecuteLoadingTasksAsync(); // 加载完成后关闭加载界面,进入主程序 this.Close(); } private async Task ExecuteLoadingTasksAsync() { // 按顺序执行各个加载任务,每个任务完成后更新进度 await LoadConfigurationAsync(); UpdateProgress(); await LoadGameTexturesAsync(); UpdateProgress(); await LoadDatabaseDataAsync(); UpdateProgress(); await InitializeApplicationStateAsync(); UpdateProgress(); }
3. 真实加载任务示例
把下面的模拟代码替换成你实际的加载逻辑(比如读取文件、调用API、初始化资源等):
// 加载配置文件 private async Task LoadConfigurationAsync() { // 这里替换为真实的配置读取/解析代码 await Task.Delay(1200); } // 加载纹理资源 private async Task LoadGameTexturesAsync() { // 这里替换为真实的纹理加载代码(比如从本地读取图片资源) await Task.Delay(3500); } // 加载数据库数据 private async Task LoadDatabaseDataAsync() { // 这里替换为真实的数据库查询/初始化代码 await Task.Delay(2000); } // 初始化应用状态 private async Task InitializeApplicationStateAsync() { // 这里替换为真实的应用状态初始化代码 await Task.Delay(800); }
4. 安全更新进度条
因为加载任务在后台线程执行,必须回到UI线程更新进度条控件:
private void UpdateProgress() { _completedTasks++; // 计算当前进度百分比 int currentProgress = (int)((double)_completedTasks / _totalLoadingTasks * 100); // 确保在UI线程更新控件 if (percentageBar.InvokeRequired) { percentageBar.Invoke(new Action(UpdateProgress)); return; } percentageBar.Value = currentProgress; }
进阶:按字节数跟踪进度(加载大文件)
如果你的加载任务是大文件(比如游戏资源包),可以按已加载字节数计算进度:
private long _totalFileSize = 0; private long _loadedBytes = 0; private async Task LoadLargeAssetFileAsync() { string filePath = "path/to/your/large/asset.file"; using (var fileStream = new FileStream(filePath, FileMode.Open)) { _totalFileSize = fileStream.Length; byte[] buffer = new byte[4096]; int bytesRead; // 分块读取文件,每次读取后更新进度 while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length)) > 0) { _loadedBytes += bytesRead; int progress = (int)((double)_loadedBytes / _totalFileSize * 100); UpdateProgressByBytes(progress); } } } private void UpdateProgressByBytes(int progress) { if (percentageBar.InvokeRequired) { percentageBar.Invoke(new Action<int>(UpdateProgressByBytes), progress); return; } percentageBar.Value = progress; }
关键注意事项
- 所有耗时的加载操作必须用
async/await包装,避免阻塞UI线程 - 永远不要在后台线程直接操作UI控件,必须用
Invoke回到UI线程 - 总任务数/总字节数要根据实际情况准确设置,这样进度计算才会精准
内容的提问来源于stack exchange,提问作者AngryCDeveloper
相关产品推荐
相关产品推荐

