【问题标题】:Pass different method/function to DoWork event of Background worker将不同的方法/函数传递给后台工作人员的 DoWork 事件
【发布时间】:2015-04-27 07:11:52
【问题描述】:

请原谅我对这个主题和我使用的术语的无知。不正确的地方请指正。

我在我的表单上使用了工具箱中的后台 Worker,并且我正在将一个方法传递给 DoWork 事件。在第一次尝试使用后台 Worker 时,我了解到我可以使用仅为 1 个任务创建的后台 Worker。见以下代码:

private void btn1_Click(object sender, EventArgs e)
{
   // Should call the uploadToDB1 using BackgroundWorker's DoWork event.
     backgroundWorker1.RunWorkerAsync();
}

private void btn2_Click(object sender, EventArgs e)
{
    // Should call the uploadToDB2 using BackgroundWorker's DoWork event.
    backgroundWorker1.RunWorkerAsync();
}

private void uploadToDB1()
{
    // Code for uploading to DB 1.
}        

private void uploadToDB2()
{
    // Code for uploading to DB 2.
}  

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    try
    {

        uploadToDB1(); // I want to change this to uploadToDB2 i.e. a variable method, How do I assign a call to this?

    }
    catch (Exception ex)
    {

        MessageBox.Show(ex.Message);
    }

}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar1.Visible = true;
    progressBar1.Maximum = maxRecords;
    lblProgress.Text = Convert.ToString(e.ProgressPercentage.ToString() + "/" + maxRecords);
    progressBar1.Value = e.ProgressPercentage;

}

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    progressBar1.Visible = false;
    lblProgress.Text = "";
}

我需要能够动态地将方法传递给 DoWork 事件,而无需创建多个后台 Worker,因为与后台 Worker 相关的其余事件中的操作保持不变。

您能告诉我应该怎么做吗?

使用 TPL 更新了代码,但是我遇到了跨线程错误。你能帮忙改正代码吗?只有在上传到 DB 1 完成后才会上传到 DB 2。因此,每次上传时,标签和进度条都需要更新。我还需要将不同的文本传递给标签。

private void btn1_Click(object sender, EventArgs e)
{
    Task.Factory.StartNew(uploadToDB1);
}
private void uploadToDB1()
{
    for(i=0;i<dt.rows.count-1;i++)
    {
        // Code for inserting into DB1.

        progressbar1.maximum=dt.rows.count-1;
        progressbar1.value=i;
    }
    uploadToDB2();

}

private void uploadToDB2()
{
    for(i=0;i<dt.rows.count-1;i++)
    {
        // Code for inserting into DB2.

        progressbar1.maximum=dt.rows.count-1;
        progressbar1.value=i;
    }

}

【问题讨论】:

  • 为什么不创建两个后台工作人员,每个工作一个?
  • 为什么不直接抛出 BackgroundWorker 并使用 TPL?
  • 策略模式也可能对您有所帮助
  • @SriramSakthivel BackgroundWorker 适用于 l33t。
  • @YuvalItzchakov,是的,我确实想到了这一点,但正如我所提到的,backgroundWorker 的其他事件中的操作是相同的。如果可能的话,我希望能够重用代码。

标签: c# backgroundworker


【解决方案1】:

可以做的,有点小技巧,就是将Action作为调用参数传递给DoWorkAsync

var bw = new BackgroundWorker();
bw.DoWork += (s, o) => 
{
    Action actualWork = (Action)o.Argument;
    actualWork();
}

当你调用DoWorkAsync:

Action action = () => DoSomething();
bw.RunWorkerAsync(action);

相反,正如@Sriram 建议的那样,查看Task Parallel Library,这将使您的生活更轻松:

private async void btn1_Click(object sender, EventArgs e)
{
    await Task.Run(UpdateFirst);
    // Update UI here.
}

private async void btn2_Click(object sender, EventArgs e)
{
    await Task.Run(UpdateSecond);
    // Update UI again.
}

关于 TPL 和IProgess&lt;T&gt; 的使用的广泛答案可以在How to provide a feedback to UI in a async method? 中找到

【讨论】:

  • 有两个 answers here 几乎总结了 OP 想要什么。使用 IProgress&lt;T&gt; 和 TPL 向 UI 提供反馈。
  • @SriramSakthivel 现在你告诉我? :\
  • 这可以让我更新标签和进度条吗?如果是这样,我该怎么做?我问的原因是,我一直在努力使用与实际上传进度相匹配的进度条,并且第一次使用 backgroundWorker 它就像一个魅力。
  • @svb 查看提供的链接。我还更新了我的答案以包含该链接,因为它有更广泛的答案。
  • @svb 您正在使用后台工作人员进行上传?使用await 和异步 I/O 很容易处理,不需要单独的线程。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多