为何/如何在不使用DoWorkEventArgs的情况下使用BackgroundWorker?
如何在不使用DoWorkEventArgs的情况下使用BackgroundWorker
其实这个需求完全可以实现,核心思路就是利用你的ReportBuilder类自身的成员变量来管理输入、输出数据,而不是依赖DoWorkEventArgs的Argument或Result属性。毕竟你的类已经持有了apiObject和selectedProjects这些关键数据,后台线程直接访问这些成员就足够了。
下面是修改并完善后的代码示例,适配你的需求:
class ReportBuilder { private List<Project> projects; private List<Invoice> invoices; private MyAPI apiObject; // 自定义事件,方便UI层监听进度和完成状态 public event ProgressChangedEventHandler ProgressUpdated; public event RunWorkerCompletedEventHandler WorkCompleted; public ReportBuilder(MyAPI apiAccess, List<Project> selectedProjects){ this.apiObject = apiAccess; this.projects = selectedProjects; this.invoices = new List<Invoice>(); // 初始化结果集合 } public void DownloadData(){ BackgroundWorker workerThread = new BackgroundWorker(); // 如果需要进度更新或取消功能,开启这两个开关 workerThread.WorkerReportsProgress = true; workerThread.WorkerSupportsCancellation = true; // DoWork委托中直接使用类的成员变量,完全不需要DoWorkEventArgs的参数 workerThread.DoWork += (sender, e) => { var worker = sender as BackgroundWorker; int processedCount = 0; foreach (var project in projects) { // 检查是否有取消请求 if (worker.CancellationPending) { e.Cancel = true; break; } // 调用API获取当前项目的发票 var projectInvoices = apiObject.GetInvoicesForProject(project.Id); invoices.AddRange(projectInvoices); // 计算并报告进度 processedCount++; int progress = (int)((processedCount / (double)projects.Count) * 100); worker.ReportProgress(progress); } }; // 将后台线程的进度事件转发给类的自定义事件,方便UI层处理 workerThread.ProgressChanged += (sender, e) => { ProgressUpdated?.Invoke(this, e); }; // 工作完成后的处理,同样利用类成员获取结果,不用依赖e.Result workerThread.RunWorkerCompleted += (sender, e) => { if (e.Error != null) { // 这里可以添加错误处理逻辑,比如通知UI层出错了 } else if (e.Cancelled) { // 处理用户取消操作的场景 } else { // 此时this.invoices已经填充完成,可以供外部调用 } // 通知UI层工作完成 WorkCompleted?.Invoke(this, e); }; // 启动后台任务 workerThread.RunWorkerAsync(); } // 提供一个安全的方法让外部获取结果(建议在WorkCompleted事件触发后调用) public List<Invoice> GetInvoices() { // 返回副本避免外部直接修改内部集合,保证线程安全 return new List<Invoice>(invoices); } }
关键要点说明
- 抛弃DoWorkEventArgs的核心逻辑:你的类已经封装了所有需要的输入(
apiObject、projects)和输出(invoices)数据,后台线程可以直接访问这些成员,完全不需要通过e.Argument传递参数,也不用e.Result返回结果。 - 进度与取消支持:如果需要这些功能,只需开启
BackgroundWorker对应的属性,在DoWork委托中检查取消状态、报告进度即可,最后通过自定义事件把状态传递给UI层。 - 线程安全注意:获取结果时返回集合的副本,并且建议在
WorkCompleted事件触发后再调用GetInvoices,避免UI线程和后台线程同时操作集合导致的冲突。
内容的提问来源于stack exchange,提问作者Rhydgaled
相关产品推荐
相关产品推荐

