Make a BackgroundWorker do several operations sequentially without freezing the form
Solution 1:
The solution is simple: have one BGW execute all of the commands, not just one BGW for each command. You'll need a List<svnCommand>
to store the commands so you can easily pass them to RunWorkerAsync(). DoWork() can simply iterate the list with foreach.
Solution 2:
So nobugz give you already the right direction, but for completeness here is some sample code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace Threading
{
public partial class FormMain : Form
{
private BackgroundWorker _BackgroundWorker;
private Queue<Func<string>> _Commands;
private Random _Random;
public FormMain()
{
InitializeComponent();
_Random = new Random();
_Commands = new Queue<Func<string>>();
_BackgroundWorker = new BackgroundWorker();
_BackgroundWorker.WorkerReportsProgress = true;
_BackgroundWorker.WorkerSupportsCancellation = true;
_BackgroundWorker.DoWork += backgroundWorker_DoWork;
_BackgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;
_BackgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
_BackgroundWorker.RunWorkerAsync();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
while (!_BackgroundWorker.CancellationPending)
{
if (_Commands.Count > 0)
{
AddMessage("Starting waiting job...");
AddMessage(_Commands.Dequeue().Invoke());
}
Thread.Sleep(1);
}
}
void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
AddMessage("BackgroundWorker doesn't make any further jobs.");
}
private void buttonStart_Click(object sender, EventArgs e)
{
_Commands.Enqueue(DoSomething);
//or maybe with a lambda
//_Commands.Enqueue(new Func<string>(() =>
//{
// string message;
// message = DoSomething();
// return message;
//}));
}
private string DoSomething()
{
int max = 10;
for (int i = 1; i <= max; i++)
{
Thread.Sleep(_Random.Next(10, 1000));
if (_BackgroundWorker.CancellationPending)
{
return "Job aborted!";
}
AddMessage(String.Format("Currently working on item {0} of {1}", i, max));
_BackgroundWorker.ReportProgress((i*100)/max);
}
return "Job is done.";
}
private void AddMessage(string message)
{
if (textBoxOutput.InvokeRequired)
{
textBoxOutput.BeginInvoke(new Action<string>(AddMessageInternal), message);
}
else
{
AddMessageInternal(message);
}
}
private void AddMessageInternal(string message)
{
textBoxOutput.AppendText(String.Format("{0:G} {1}{2}", DateTime.Now, message, Environment.NewLine));
textBoxOutput.SelectionStart = textBoxOutput.Text.Length;
textBoxOutput.ScrollToCaret();
}
private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
{
if (_BackgroundWorker.IsBusy)
{
_BackgroundWorker.CancelAsync();
e.Cancel = true;
AddMessage("Please close only if all jobs are done...");
}
}
}
}