C # BackGroundWorker с ProgressBar Обновления после завершения процесса - PullRequest
2 голосов
/ 19 апреля 2011

У меня есть следующее в событии нажатия кнопки:

private void buttonSubmitAchChecks_Click(object sender, EventArgs e)
{
  if (backgroundWorker1.IsBusy) return;
  SubmittingAch(true);

  backgroundWorker1.WorkerReportsProgress = true;
  backgroundWorker1.WorkerSupportsCancellation = true;

  label_Status.Text = "Submitting checks to ACH ....";
  var qry = from ds in checkTrans.IndividualCheck
            where ds.SubmitToACH &&
                  ds.Status == "Entered" &&
                  ds.CheckAmount > 0 &&
                  ds.SubmitToACH
            select ds;

  if (qry.Count() <= 0)
  {
    label_Status.Text = "Nothing to submit. Check the Check Amount, ACH, and Status fields.";
  }
  else
  {
    progressBar1.Maximum = qry.Count();
    progressBar1.Minimum = 0;
    progressBar1.Step = 1;
    backgroundWorker1.RunWorkerAsync(qry);
  }

}

Мой фонWorker1_DoWork:

private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
  if (backgroundWorker1.CancellationPending)
  {
    e.Cancel = true;
  }
  else
  {
    var qry = e.Argument as EnumerableRowCollection<CheckTrans.IndividualCheckRow>;
    if (qry != null)
    {
      Thread.Sleep(4000);

      //item.Status = ach.SubmitCheck(item);
      var ach = new SubmitAchChecks();
      foreach (var item in qry)
      {
        ach.SubmitCheck(item);
        backgroundWorker1.ReportProgress(1);
        Console.Write("backgroundWorker1_dowork=" + progressBar1.Value.ToString() + "\r\n");
      }
    }

  }

}

Моя кнопка отмены:

private void cancelAsyncButton_Click(object sender, EventArgs e)
{
  if (backgroundWorker1.WorkerSupportsCancellation == true)
  {
    label_Status.Text = "Cancelling...";
    backgroundWorker1.CancelAsync();
  }
}

Мой фонWorker1_RunWorkerCompleted:

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  if (e.Cancelled == true)
  {
    label_Status.Text = "Canceled!";
  }
  else if (e.Error != null)
  {
    label_Status.Text = "Error: " + e.Error.Message;
  }
  else
  {
    label_Status.Text = "Done!";
  }
  SubmittingAch(false);
}

Мой фонWorker1_ProgressChanged:

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
  progressBar1.Value += 1;
  Console.Write("progressbar1.value=" + progressBar1.Value.ToString() + "\r\n");
}

Я получаю следующий вывод в окне отладки, когда обработал 2 элемента:

backgroundWorker1_dowork = 0

backgroundWorker1_dowork = 0

progressbar1.value = 1

progressbar1.value = 2

Событие запускается, но, как вы можете видеть из console.write, оно происходит ПОСЛЕ завершения потока. Я получаю прокрутку индикатора выполнения, но только после завершения работы.

Что я сделал не так по этому поводу? Я хочу обновить его после завершения каждого элемента.

1 Ответ

3 голосов
/ 19 апреля 2011

Это связано с тем, как работают потоки.ProgressChange вызывается в потоке пользовательского интерфейса с использованием BeginInvoke и, следовательно, в другом потоке.Тем временем рабочий поток продолжает работать.Поскольку работы не так много, BackgroundWorker завершает свою работу до того, как BeginInvoke фактически вызовет метод, потому что переключение потоков происходит не при каждой операции ЦП.Они случаются после нескольких.Чтобы избежать этого, вручную вызовите метод, который увеличивает значение ProgressBar, используя this.Invoke().

...