BackgroundWorker进度条不更新求助:遍历文件时进度无动态变化
BackgroundWorker进度条不更新&完成事件不触发的问题修复
咱们先直接说你代码里的核心问题:你把整个DoWork方法里的逻辑都套在了Dispatcher.Invoke里!这完全违背了BackgroundWorker的设计初衷——BackgroundWorker本来就是要把耗时操作放在后台线程执行,避免UI线程卡顿,结果你这操作直接把所有工作都扔回UI线程跑了,进度报告自然没法实时推送,UI线程被占满后,RunWorkerCompleted事件也根本没机会触发。
除此之外还有两个小问题:
- 进度计算公式错误,导致百分比不符合你的预期
- 后台线程里直接调用
MessageBox.Show,这会阻塞后台线程,而且不符合线程安全规范
下面是修正后的完整代码,我会标注关键修改点:
private void CSV_Click(object sender, RoutedEventArgs e) { try { btnExtract.IsEnabled = false; // 确保BackgroundWorker的WorkerReportsProgress属性设为true! workerextract.WorkerReportsProgress = true; workerextract.RunWorkerAsync(); } catch (Exception ex) { System.Windows.MessageBox.Show(ex.Message); } } private void workerextract_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) { try { // 这里不要用Dispatcher.Invoke!直接在后台线程获取文件列表 DirectoryInfo di = new DirectoryInfo(txtQueryfolder.Text); var sqlFiles = di.GetFiles("*.sql"); int filesCount = sqlFiles.Length; int currentFile = 0; foreach (FileInfo fi in sqlFiles) { // 读取文件、处理数据的逻辑都在后台线程执行 using (StreamReader sr = new StreamReader(fi.FullName)) { string line = sr.ReadToEnd(); ExtractToCSV(line, System.IO.Path.GetFileNameWithoutExtension(fi.Name)); currentFile++; } // 计算正确的进度百分比:已完成数/总数*100 int percentage = currentFile * 100 / filesCount; // 后台线程直接调用ReportProgress,框架会自动把进度事件抛到UI线程 workerextract.ReportProgress(percentage); } } catch (Exception ex) { // 后台线程的异常不要直接弹框,通过e.Result或者e.Error传递给Completed事件 e.Error = ex; } } private void workerextract_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e) { progressBarExtract.Value = e.ProgressPercentage; } private void workerextract_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { btnExtract.IsEnabled = true; // 处理后台线程的异常 if (e.Error != null) { System.Windows.MessageBox.Show($"提取失败:{e.Error.Message}"); return; } System.Windows.MessageBox.Show("CSV Data extraction finished!"); }
关键修改说明:
- 移除了DoWork里的
Dispatcher.Invoke:所有文件读取、数据处理的逻辑都在后台线程执行,只让UI线程负责更新进度条(ProgressChanged事件会自动在UI线程触发)。 - 修正了进度计算逻辑:用
currentFile * 100 / filesCount,这样第一个文件完成后就是1*100/20=5%,完全符合你的预期。 - 后台线程异常处理优化:不再直接在DoWork里弹框,而是把异常赋值给
e.Error,在RunWorkerCompleted事件里统一处理,避免后台线程阻塞。 - 确保WorkerReportsProgress属性为true:这是BackgroundWorker能触发ProgressChanged事件的前提,你之前的代码里可能没设置这个属性(如果XAML里没设的话,代码里要加上)。
这样修改后,进度条会实时更新,每个文件完成后都会触发ProgressChanged事件,RunWorkerCompleted事件也会在所有工作完成后正常触发,弹出完成提示。
内容的提问来源于stack exchange,提问作者Firdavs Kurbonov
相关产品推荐
相关产品推荐

