在VSTO Excel加载项中向另一个类传递Background Worker
实现跨类传递进度的方案(适配你的VSTO Excel加载项场景)
既然你已经把业务逻辑和UI层做了分离,那核心目标就是让业务类能够汇报进度,同时又不直接依赖UI层的BackgroundWorker(避免耦合)。下面是几个实用的方案,按推荐程度排序:
方案1:给业务类添加进度事件(低耦合,推荐)
这个方案让业务类只负责触发进度事件,UI层负责订阅并通过BackgroundWorker汇报到UI,完全符合分离原则。
第一步:改造业务类,添加进度事件
public class YourBusinessClass { // 定义进度更新事件,参数用.NET自带的ProgressChangedEventArgs就行 public event EventHandler<ProgressChangedEventArgs> ProgressUpdated; // 封装触发事件的方法(私有,内部调用) private void RaiseProgressUpdated(int progressPercent, object statusMsg) { // 空值判断,避免没订阅时抛出异常 ProgressUpdated?.Invoke(this, new ProgressChangedEventArgs(progressPercent, statusMsg)); } // 你的业务方法示例 public void ExecuteQueryAndFillSheet(bool isExtended) { // 模拟业务逻辑:比如循环处理数据 for (int i = 0; i <= 100; i++) { // 这里替换成你的实际业务操作(比如查询、填充工作表) Thread.Sleep(30); // 模拟耗时操作 // 触发进度事件 RaiseProgressUpdated(i, $"正在处理:{i}%"); } } }
第二步:在BackgroundWorker的DoWork中订阅事件
private void backgroundWorker3_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker worker = (BackgroundWorker)sender; var ol = new YourBusinessClass(); var ole = new YourExtendedBusinessClass(); // 假设你有另一个业务类 // 订阅业务类的进度事件 ol.ProgressUpdated += (s, args) => { // 先检查用户是否取消了操作 if (worker.CancellationPending) { e.Cancel = true; return; } // 通过BackgroundWorker汇报进度到UI worker.ReportProgress(args.ProgressPercentage, args.UserState); }; // 如果ole也需要汇报进度,同样订阅它的事件 ole.ProgressUpdated += (s, args) => { if (worker.CancellationPending) { e.Cancel = true; return; } worker.ReportProgress(args.ProgressPercentage, args.UserState); }; // 执行业务逻辑 if (!_isExtended) { ol.ExecuteQueryAndFillSheet(false); } else { ole.ExecuteQueryAndFillSheet(true); } }
第三步:处理BackgroundWorker的ProgressChanged事件(UI层)
private void backgroundWorker3_ProgressChanged(object sender, ProgressChangedEventArgs e) { // 这里更新你的UI控件,比如进度条、状态标签 yourProgressBar.Value = e.ProgressPercentage; statusLabel.Text = e.UserState.ToString(); }
方案2:使用IProgress接口(更灵活,适配.NET 4.5+)
这个方案用.NET内置的抽象接口IProgress<T>,让业务类完全依赖抽象,和UI层的具体实现(比如BackgroundWorker)彻底解耦,非常适合测试和复用。
第一步:改造业务类,注入IProgress
public class YourBusinessClass { private readonly IProgress<(int Percent, string Message)> _progress; // 构造函数注入进度接口 public YourBusinessClass(IProgress<(int Percent, string Message)> progress) { _progress = progress; } public void ExecuteQueryAndFillSheet(bool isExtended) { for (int i = 0; i <= 100; i++) { // 实际业务操作 Thread.Sleep(30); // 汇报进度 _progress.Report((i, $"处理中:{i}%")); } } }
第二步:在DoWork中创建Progress实例并传递给业务类
private void backgroundWorker3_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker worker = (BackgroundWorker)sender; // 创建Progress实例,它会自动在UI线程处理进度更新 var progress = new Progress<(int Percent, string Message)>(update => { if (worker.CancellationPending) { e.Cancel = true; return; } worker.ReportProgress(update.Percent, update.Message); }); // 实例化业务类并传入进度接口 var ol = new YourBusinessClass(progress); // 如果ole也需要,同样传入progress var ole = new YourExtendedBusinessClass(progress); // 执行业务逻辑 if (!_isExtended) { ol.ExecuteQueryAndFillSheet(false); } else { ole.ExecuteQueryAndFillSheet(true); } }
第三步:同样处理ProgressChanged事件(和方案1一样)
private void backgroundWorker3_ProgressChanged(object sender, ProgressChangedEventArgs e) { yourProgressBar.Value = e.ProgressPercentage; statusLabel.Text = e.UserState.ToString(); }
方案3:直接传递BackgroundWorker引用(不推荐,耦合度高)
如果只是快速实现,你也可以直接把BackgroundWorker传给业务类,但这样业务类会依赖UI层的组件,不利于后续维护和测试,所以只作为应急方案:
// 业务类直接持有BackgroundWorker引用 public class YourBusinessClass { private readonly BackgroundWorker _worker; public YourBusinessClass(BackgroundWorker worker) { _worker = worker; } public void ExecuteQueryAndFillSheet(bool isExtended) { for (int i = 0; i <= 100; i++) { if (_worker.CancellationPending) break; // 业务操作 Thread.Sleep(30); // 直接调用ReportProgress _worker.ReportProgress(i, $"处理:{i}%"); } } } // DoWork中传递引用 private void backgroundWorker3_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker worker = (BackgroundWorker)sender; var ol = new YourBusinessClass(worker); ol.ExecuteQueryAndFillSheet(!_isExtended); }
关键注意事项
- 一定要在窗体初始化时开启
BackgroundWorker的进度汇报和取消支持:
backgroundWorker3.WorkerReportsProgress = true; backgroundWorker3.WorkerSupportsCancellation = true;
- 在业务逻辑中要定期检查
CancellationPending,及时终止操作,避免无效执行。
内容的提问来源于stack exchange,提问作者LCaraway
相关产品推荐
相关产品推荐

