如何使用ProgressBar、Progress和IProgress<int>显示Task进度
解决ProgressBar不更新及异步文件扫描问题
核心问题定位
你的代码存在几个关键错误导致进度条无响应,同时有异步编程的不规范用法:
- 进度回调中误用未定义的变量
i,而非Progress<int>传入的value参数 - 对空的
BindingList<Game>直接使用索引赋值,会抛出异常且无法正确添加元素 - 异步方法中用
.Result阻塞线程,导致UI假死 - 未提前设置ProgressBar的最大值,可能导致进度值超出范围
修正后的完整代码
调用代码(UI线程中执行)
// 先设置进度条最大值,可根据实际文件数量动态调整 pbCopy.Maximum = 400; pbCopy.Value = 0; var progress = new Progress<int>(value => { // 使用回调传入的value参数,处理边界值 pbCopy.Value = value > pbCopy.Maximum ? pbCopy.Maximum : value; }); // 异步执行扫描,获取结果后绑定到DataGridView var gamesList = await getGamesTask(folder, progress); yourDataGridView.DataSource = gamesList;
异步文件扫描方法
private async Task<IBindingList> getGamesTask(string folder, IProgress<int> progress) { string[] filters = new[] { "iso", "gcm" }; // 优先用异步等待替代.Result,避免阻塞线程 // 如果GetFilesFolder是同步方法,改用Task.Run包装: // string[] files = await Task.Run(() => GetFilesFolder(folder, filters, true)); string[] files = await GetFilesFolder(folder, filters, true); var games = new BindingList<Game>(); for (int j = 0; j < files.Length; j++) { var file = files[j]; // 提取游戏信息(如果GetGameInfo耗时,建议异步化) var game = GetGameInfo(file); // 用Add方法添加元素,而非直接索引赋值 games.Add(game); // 报告当前进度,j+1让进度从1开始,更符合直觉 progress?.Report(j + 1); } return games; }
手动使用BeginInvoke的场景(可选)
如果因特殊需求需要手动切换到UI线程更新进度条,可修改Progress回调如下:
var progress = new Progress<int>(value => { if (pbCopy.InvokeRequired) { // 异步切换到UI线程更新进度 pbCopy.BeginInvoke(new Action<int>(v => { pbCopy.Value = v > pbCopy.Maximum ? pbCopy.Maximum : v; }), value); } else { pbCopy.Value = value > pbCopy.Maximum ? pbCopy.Maximum : value; } });
注:
Progress<int>默认会捕获创建时的UI线程上下文,自动在UI线程执行回调,因此大多数场景下不需要手动调用BeginInvoke。
内容的提问来源于stack exchange,提问作者sJohnson1021
相关产品推荐
相关产品推荐

