From your question it appears that you have multiple rows in the grid that need to be processed. Now the background worker executes the method in another thread thus freeing up the UI to perform additional actions. (IE status updates). As this is executed on another thread the UI is free to continue processing as normal. The UI thread will not wait for the BackgroundWorker to finish. If it did wait, there would be no use using the background worker. Additionally the BackgroundWorker must finish the operation before starting another operation (thus your error message).
Now it is hard to understand what you are doing in the work.doTheWork()
but I suspect you would want to take another approach here.
Before we begin tackling the question the first thing you must understand is the Cancellation of a background worker doesn't actually cancel the thread but provides a "flag" for your code to check if the BackgroundWorker is pending calculation (MSDN on this flag ).
Moving forward. As the Grid is held on the UI thread you need to understand the data from the grid that we want to capture and pass it into the BackgroundWorker context. As this inst provided I am going to do a very basic example. Now you could run multiple background workers to process each row individually thus spawning 1 worker per row in the Grid. For your requirement this may be ideal but for larger grids you are essentially creating 1 thread per row to process and in a grid with hundreds of rows this could be disastrous.
So to being you can create a method something like below. I have commented the code to help you run through it. Bascially this shows the ability to cancel the worker, report progress and iterate through each row item individually. I also added some basic classes for use inside the worker. [Note this is demo code only]
class DoWorkTester
{
int currentIndex = 0;
GridRow[] rows;
public void ExecuteWorkers()
{
GridRow rowA = new GridRow
{
PropertyA = "abc",
PropertyB = "def"
};
GridRow rowB = new GridRow
{
PropertyA = "123",
PropertyB = "456"
};
GridRow rowC = new GridRow
{
PropertyA = "xyz",
PropertyB = "789"
};
rows = new GridRow[] { rowA, rowB, rowC };
currentIndex = 0;
runWorkers();
}
BackgroundWorker worker;
void runWorkers()
{
//done all rows
if (currentIndex >= rows.Length - 1)
return;
//is the worker busy?
if (worker != null && worker.IsBusy)
{
//TODO: Trying to execute on a running worker.
return;
}
//create a new worker
worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
worker.WorkerReportsProgress = true;
worker.ProgressChanged += (o, e) =>
{
//TODO: Update the UI that the progress has changed
};
worker.DoWork += (o, e) =>
{
if (currentIndex >= rows.Length - 1)
{
//indicate done
e.Result = new WorkResult
{
Message = "",
Status = WorkerResultStatus.DONE
};
return;
}
//check if the worker is cancelling
else if (worker.CancellationPending)
{
e.Result = WorkResult.Cancelled;
return;
}
currentIndex++;
//report the progress to the UI thread.
worker.ReportProgress(currentIndex);
//TODO: Execute your logic.
if (worker.CancellationPending)
{
e.Result = WorkResult.Cancelled;
return;
}
e.Result = WorkResult.Completed;
};
worker.RunWorkerCompleted += (o, e) =>
{
var result = e.Result as WorkResult;
if (result == null || result.Status != WorkerResultStatus.DONE)
{
//TODO: Code for cancelled \ failed results
worker.Dispose();
worker = null;
return;
}
//Re-call the run workers thread
runWorkers();
};
worker.RunWorkerAsync(rows[currentIndex]);
}
/// <summary>
/// cancel the worker
/// </summary>
void cancelWorker()
{
//is the worker set to an instance and is it busy?
if (worker != null && worker.IsBusy)
worker.CancelAsync();
}
}
enum WorkerResultStatus
{
DONE,
CANCELLED,
FAILED
}
class WorkResult
{
public string Message { get; set; }
public WorkerResultStatus Status { get; set; }
public static WorkResult Completed
{
get
{
return new WorkResult
{
Status = WorkerResultStatus.DONE,
Message = ""
};
}
}
public static WorkResult Cancelled
{
get
{
return new WorkResult
{
Message = "Cancelled by user",
Status = WorkerResultStatus.CANCELLED
};
}
}
}
class GridRow
{
public string PropertyA { get; set; }
public string PropertyB { get; set; }
}
Now if you wanted to process multiple rows at a time you will have to adapt the code to use some sort of Worker Pooling or pass all the row data to the first background worker thus removing the recursion.
Cheers.