使用不同类的C#,报告BackgroundWorker的进度

16
在我的.NET C#项目中,我使用了“BackgroundWorker”来调用不同类中的方法。以下是我的主窗体的源代码。
public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        testClass t1 = new testClass();
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            t1.changevalue(1000);
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            label1.Text += Convert.ToString(e.ProgressPercentage);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            backgroundWorker1.RunWorkerAsync();
        }
    }

我希望您能够在我的项目中,将以下代码放入名为“testClass.cs”的单独类文件中。我希望能够从这个类中向后台工作者报告进度,以便能够在主表单 label1 中显示进度。

class testClass
    {
        private int val;
        public int changevalue(int i)
        {
            for (int j = 0; j < 1000; j++)
            {
                val += i + j;
                //from here i need to preport the backgroundworker progress
                //eg; backgroundworker1.reportProgress(j);
            }
            return val;
        }
    } 

但是我无法从“testClass”访问BackgroundWorker。

有人可以告诉我如何解决这个问题吗?

p.s- 我发现这个解决方案,但我不理解它。

3个回答

33

你可以将它作为变量传递

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    t1.changevalue(1000, sender as BackgroundWorker);
}


class testClass
{
    private int val;
    public int changevalue(int i, BackgroundWorker bw)
    {
        for (int j = 0; j < 1000; j++)
        {
            val += i + j;
            bw.ReportProgress(i);
            //from here i need to preport the backgroundworker progress
            //eg; backgroundworker1.reportProgress(j);
        }
        return val;
    }
} 

但是我认为最好的选择是在testClass中创建一个event,让您的Form可以赋值给它。

public partial class Form1 : Form
{
    private BackgroundWorker backgroundWorker1;
    private testClass t1 = new testClass();

    public Form1()
    {
        InitializeComponent();

        // subscribe to your event
        t1.OnProgressUpdate += t1_OnProgressUpdate;
    }

    private void t1_OnProgressUpdate(int value)
    {
        // Its another thread so invoke back to UI thread
        base.Invoke((Action)delegate
        {
            label1.Text += Convert.ToString(value);
        });
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        t1.changevalue(1000);
    }

    private void button1_Click_1(object sender, EventArgs e)
    {
        backgroundWorker1.RunWorkerAsync();
    }

}

class testClass
{
    public delegate void ProgressUpdate(int value);
    public event ProgressUpdate OnProgressUpdate;

    private int val;
    public int changevalue(int i)
    {
        for (int j = 0; j < 1000; j++)
        {
            val += i + j;

            // Fire the event
            if (OnProgressUpdate != null)
            {
                OnProgressUpdate(i);
            }
        }
        return val;
    }
} 

非常感谢 @sa_ddam213 先生。这正是我一直在寻找的。你的代码运行得非常好。干杯! - PIKP
你的第二个解决方案看起来有点难以阅读。你为什么认为它比第一个更好呢? - Nolonar
3
@Nolonar,第二个版本将BackgroundWorker与逻辑类分离开来,不仅如此,该类现在可以返回进度而不管它是否与BackgroundWorker一起使用,你只需要订阅'OnProgressUpdate'事件就可以了。 - sa_ddam213

1

我刚遇到了同样的问题(我的长时间运行的进程是数据库恢复),通过在另一个类中引发事件来以类似的方式解决了这个问题,但是我的事件订阅者只是作为backgroundWorker1.ReportProgress()的包装器。

private void DBRestoreProgressHandler(DataAccess da, DataAccess.DatabaseRestoreEventArgs e)
    {
        backgroundWorker1.ReportProgress(e.RestoreProgress);
    }

private void backgroundWorker1_ReportProgress(object sender, ProgressChangedEventArgs e)
    {
        someLabel.Text = e.ProgressPercentage.ToString();
    }

这样就不用使用以下代码了:

base.Invoke((Action)delegate

我认为如果表单意外关闭,这可能会导致问题?

-2
我在上面的代码中漏掉了什么吗?:
backgroundWorker1 = new BackgroundWorker();
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);

4
我不确定这是否合格作为答案。你觉得呢? - PilouPili

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