You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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);
}

关键注意事项

  1. 一定要在窗体初始化时开启BackgroundWorker的进度汇报和取消支持:
backgroundWorker3.WorkerReportsProgress = true;
backgroundWorker3.WorkerSupportsCancellation = true;
  1. 在业务逻辑中要定期检查CancellationPending,及时终止操作,避免无效执行。

内容的提问来源于stack exchange,提问作者LCaraway

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:27:28