c#后台工作者(BackgroundWorker)如何调用另一个类的DoWork方法并进行进度报告(ProgressReport)

3

我正在运行一个BackgroundWorker线程来执行耗时任务。这个耗时任务在另一个类中。我需要将在BackgroundWorker上运行的这个独立类的进度传回到主Form1类。我不确定如何解决这个问题,请提供建议。谢谢您的帮助。

    **// Main Form1 UI Class**    

    public void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
    {
        //e.Argument always contains whatever was sent to the background worker
        // in RunWorkerAsync. We can simply cast it to its original type.
        DataSet ds = e.Argument as DataSet;
        this.createje.ProcessData(this.ds);
    }

    private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        this.progressBar1.Minimum = 0;
        this.progressBar1.Maximum = CreateJE.max;
        this.progressBar1.Value = e.Recno;
    }

    **//Other Class called CreateJE**

    public void ProcessData(DataSet ds)
    {
        //Do time consuming task...
     for (int i = 1; i <= 10; i++)
        {
            if (worker.CancellationPending == true)
            {
                e.Cancel = true;
                break;
            }
            else
            {
                // Perform a time consuming operation and report progress.
                System.Threading.Thread.Sleep(500);

                **//How do I report progress back to the Main UI?** 
                //worker.ReportProgress(i * 10);
            }
        }
    }
2个回答

5
最干净,最易于扩展的解决方案可能是使你的ProcessData()方法引发一个事件,这个事件由BackgroundWorker监听。这样,ProcessData()不依赖于BackgroundWorker作为呼叫者。(你还需要一种方法来取消ProcessData()的操作)。如果需要,你甚至可以重新使用ProgressChangedEventArgs 。例如(未经测试,但你明白意思吧?):
partial class Form1 { 
    public void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e) {
        //e.Argument always contains whatever was sent to the background worker 
        // in RunWorkerAsync. We can simply cast it to its original type.
        DataSet ds = (DataSet)e.Argument;
        var bgw = (BackgroundWorker)sender;

        var eh = new ProgressChangedEventHandler((o,a) => bgw.ReportProgress(a.ProgressPercentage));
        createje.ProgressChanged += eh;
        this.createje.ProcessData(this.ds));
        createje.ProgressChanged -= eh; //necessary to stop listening
    }

    private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        this.progressBar1.Minimum = 0;
        this.progressBar1.Maximum = CreateJE.max;
        this.progressBar1.Value = e.ProgressPercentage;
    }

}

partial class CreateJE { 

    public event ProgressChangedEventHandler ProgressChanged; 
    protected virtual void OnProgressChanged(ProgressChangedEventArgs e)
    { 
        var hand = ProgressChanged; 
        if(hand != null) hand(this, e);
    }

    public void ProcessData(DataSet ds)
    {
        for(int i = 1; i <= 10; i++)
        {
            // Perform a time consuming operation and report progress.
            System.Threading.Thread.Sleep(500);

            var e = new ProgressChangedEventArgs(i * 10, null);
        }
    }

}

快速而简单的方法是将BackgroundWorker作为参数传递给ProcessData()。然而,这种方式不太好看,而且限制了使用BackgroundWorkers,并且还需要在一个地方(主表单类)定义BackgroundWorker并在另一个地方(CreateJE class)返回ReportProgress的值。
你还可以使用定时器每隔X毫秒报告一次进度,查询CreateJE对象的进度。这似乎与您的代码的其余部分一致。但是这种方式会使您的CreateJE类无法支持多线程。

我喜欢你的第一个建议。你能提供一个代码示例吗? - Shazam

1
最快、最简单的方法是在类CreateJE中声明一个delegate,用于报告进度,然后将其连接到BackgroundWorkerReportProgress方法。
class CreateJE
{
    public Action<int> ReportProgressDelegate{get;set;}

    public void ProcessData(DataSet ds)
    {
        for(int i = 0; i < 10; i++)
        {
            Thread.Sleep(500);
            ReportProgress(i*10);
        }
    }

    private void ReportProgress(int percent)
    {
        if(ReportProgressDelegate != null)
            ReportProgressDelegate(percent);
    }
}

在您的表单中,初始化您的实例的 ReportProgressDelegate 属性(我假设 this.createje 是该表单的一个字段,因此在 OnLoad 中进行初始化似乎是一个不错的选择):
protected override void OnLoad(EventArgs e)
{
    this.creatje.ReportProgressDelegate = worker.ReportProgress;
}

接下来,您可以使用已经拥有的事件处理程序 (backgroundWorker2_DoWorkbackgroundWorker2_DoWork)。

PS: 您应该使用相同的方法来处理 worker.CancellationPending 属性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接