首页 > 解决方案 > 线程和BackgroundWorker

问题描述

我有一个 WinForm C# 应用程序,我想执行一些可能需要几秒钟才能完成的计算。所以为了避免线程问题和应用程序冻结,我使用了BackgroundWorker。当我第一次单击按钮时,一切都很好,开始按钮变得不可见,取消按钮变得可见,并且应用程序没有冻结问题并且进度条更改成功。但是第二次,当我单击该按钮时,开始按钮在几秒钟内变得不可见,而取消按钮也变得不可见,尽管它必须是可见的,并且应用程序进入冻结状态,之后一切都变得很好。我不知道它为什么会起作用,因为我只在第一次尝试时才需要。这是我使用的代码。

注意:我已将 BackgroundWorker 表单工具箱添加到我的表单中。

private void btnStart_Click(object sender, EventArgs e)
{
     btnStart.Visible = false;
     btnCancel.Visible = true;
     progressBar1.Value = 0;
     progressBar1.Visible = true;
     backGroundWorker.RunWorkerAsync();

}

private void backGroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
   Calculate(backGroundWorker, e);
}

private void backGroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar1.Value = e.ProgressPercentage;
}

private void backGroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
   btnStart.Visible = true;
   btnCancel.Visible = false;
   progressBar1.Visible = false;
}

void Calculate(BackgroundWorker instance, DoWorkEventArgs e)
{
 
  // Do Some Works
  instance.ReportProgress(counter);

}

标签: c#winformsbackgroundworker

解决方案


你快完成了。您只是忘记让您的后台工作人员支持取消。此外:您的后台工作人员不应使用后台工作人员外部的任何内容。如果后台工作人员需要表单中的一些数据来执行任务,请在开始工作时将其作为参数传递。

使用设计器可以完成以下许多工作。如果你愿意,你可以自己编程。不要忘记在处理表单时处理后台工作人员

BackgroundWorker backgroundWorkder = new BackgroundWorker
{
    WorkerReportsProgres = true,
    WorkerSupportsCancellation = true,
}

// ensure that backgroundWorker is disposed when the form is disposed:
this.Components.Add(backgroundWorker); 
// alternative: react on event from closed

backgroundWorker.DoWork += OnDoBackGroundWork;
backgroundWorker.ProgressChanged += OnProgressReported;
backgroundWorker.RunWorkerCompleted += OnBackgroundWorkCompleted;

第一个事件处理程序将由 backgroundWorker 执行。此事件处理程序不应触及表单中的任何内容。

后面的两个事件处理程序将由主线程执行。他们可以使用表单中的项目。

private void StartBackgroundWork()
{
    // TODO: enable / disable buttons; show progress bar

    // if your backgroundWorker needs parameters:
    MyBackgroundParameters params = new MyBackgroundParameters()
    {
        Text = this.textBox1.Text,
        Value = this.comboBox1.SelectedIndex,
        ...
    };
    this.backgroundWorker.RunWorkerAsync(params);
}

private void CancelBackgroundwork()
{
    this.backgroundWorker.CancelAsync();
}

无需检查 backgroundWorker 是否已经完成。如果是这样,cancelAsync 不会做任何事情。此外,如果您要检查IsBusy,那么在您 CancelAsync 之前,backgroundWorker 可能会完成。

事件处理程序:

private void OnDoBackgroundWork(object sender, DoWorkEventArgs e)
{
    // if there are several backgroundWorkers that could call this, you should check 
    // the sender, to determine what work should be done and which parameters are passed
    BackgroundWorkder backgroundWorker = (BackgroundWorker)sender;
    MyBackGroundParameters params = (MyBackGroundParameters) e.DoWorkEventArgs;

    // use these params to do your calculations.
    // regularly, check if cancellationpending
    bool calculationFinished = false;
    while (!calculationFinished && !backgroundWorker.CancellationPending)
    {
        // do a short part of the calculation
        progress = performNextCalculationStep();
        backgroundWorker.ReportProgress(...)
        calculationFinished = ...
    }

    // if here, either calculation finished, or cancelled:
    MyBackgroundResult backgroundResult;
    if (calculationFinished)
    {
        backgroundResult = new MyBackgroundResult
        {
            ... // fill with values if completed
        };
    }
    else
    {
        // cancelled
        backgroundResult = new MyBackgroundResult
        {
            ... // fill with values if cancelled
        };
    }
    e.Result = backgroundResult;
}

在这里,我有参数在结果中指示计算是否更完整,或者它们是否被取消。如果你愿意,你也可以归还不同的对象。事件处理程序应检查对象的类型以查看计算是否已取消。

private void backGroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    btnStart.Visible = true;
   btnCancel.Visible = false;
   progressBar1.Visible = false;

   MyBackgroundResult result = (MyBackgroundResult)e.Result;
   this.ProcessResult(result);
}

不要忘记订阅表单关闭事件,并检查后台工作人员是否仍然忙碌。询问操作员是否可以取消这项工作。如果不是,则取消关闭,如果可以取消,则取消后台工作,并在事件表单关闭时等待完成。


推荐阅读