WPF MVVM项目中使用BackgroundWorker实时更新UI问题求助
问题分析
你的代码里BackgroundWorker完全没起到后台线程的作用,核心问题是Worker_DoWork里用App.Current.Dispatcher.Invoke把整个循环逻辑都放到UI线程执行,耗时操作仍在UI线程运行,自然导致界面冻结,也无法实时更新UI。另外你开启了WorkerReportsProgress=true但未订阅ProgressChanged事件,也没在后台线程调用ReportProgress传递数据更新。
修正方案
1. 订阅ProgressChanged事件
在ViewModel构造函数中添加事件订阅:
public BackgroundWorkerVM() { DoWorkCommand = new DoWorkCommand(this); worker = new BackgroundWorker(); worker.DoWork += Worker_DoWork; worker.RunWorkerCompleted += Worker_RunWorkerCompleted; worker.ProgressChanged += Worker_ProgressChanged; // 新增订阅 worker.WorkerReportsProgress = true; }
2. 修改DoWork方法,后台生成数据并报告进度
将耗时的数据生成逻辑留在后台线程,不直接操作UI线程的ObservableCollection,通过ReportProgress传递要添加的数据:
private void Worker_DoWork(object sender, DoWorkEventArgs e) { var backgroundWorker = sender as BackgroundWorker; for (int i = 0; i < 100; i++) { // 后台线程生成Person对象(模拟SQL数据读取) var person1 = new Person { PersonName = "john", Surname = "Smith", ResultChanged = true }; var person2 = new Person { PersonName = "jack", Surname = "Smith", ResultChanged = false }; // 传递待添加的集合到ProgressChanged事件 backgroundWorker.ReportProgress((i+1)*100/100, new List<Person> { person1, person2 }); Thread.Sleep(100); // 模拟SQL查询的耗时操作 } }
3. 在ProgressChanged事件中更新UI集合
ProgressChanged事件由BackgroundWorker自动调度到UI线程执行,可安全修改ObservableCollection实现实时更新:
private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e) { if (e.UserState is List<Person> personsToAdd) { foreach (var person in personsToAdd) { Persons.Add(person); } } }
4. 可选:完善Button显示
给XAML中的Button添加文本,方便操作:
<Button Grid.Row="1" Command="{Binding DoWorkCommand}" Content="加载数据"/>
关键说明
ObservableCollection仅能在UI线程修改,ProgressChanged事件自动在UI线程触发,因此在这里添加元素是安全的。- 后台线程仅负责数据获取/生成,所有UI相关操作必须在UI线程执行,优先通过
ProgressChanged事件实现,避免直接使用Dispatcher.Invoke包裹大量逻辑。
内容的提问来源于stack exchange,提问作者Gokhan
相关产品推荐
相关产品推荐

