jp2msft said:
I've found a very through example on the BackgroundWorker Class in the VS
Help, but I have a question that it does not address.
I have at least three (3) different, time-consuming tasks that I'd like to
use the BackgroundWorker Class on. Two are for database queries, and one is
for text validation.
My question is: Can the one BackgroundWorker Class be used for all three (3)
of these tasks? Some of the tasks do, on occasion, call one of the other
tasks.
If you're already running a task in the background, then there's no point to
having that task start its dependent task in the background separately. I'll
demonstrate what I mean shortly.
I see in the BackgroundWorker_DoWork method that there is a "sender" object.
Would the "sender" be the name of the function that I used to call the
BackgroundWorker's RunWorkerAsync method?
No, "sender" in an event handler is always the object that triggered the
event. You can have multiple BackgroundWorkers share the same event handler,
and "sender" would contain the BackgroundWorker that the event is actually
for. Let's put this aside for a minute.
What you could do is create your own methods that perform whatever
long-running task you need, possibly returning data. Let's say you have this:
DataTable getLotsOfData() { ... }
ValidationResults validateLotsOfText(string lotsOfText) { ... }
Now, when you need to perform one of these tasks from your UI thread, you
can call on a BackgroundWorker. You can create these programmatically or
drag them as components. Let's say you use components, as it's a little
easier. You can do it all in one BackgroundWorker, but this is harder to
program -- it's easier to use separate BackgroundWorkers for separate tasks.
(If you have lots of different tasks that need to run this way, or more than
one instance of the same task, you should create BackgroundWorkers from your
code rather than using design-time components.)
So let's say you have two BackgroundWorker components, one for LotsOfData
and the other for LotsOfText. When you need to start either of these
activities from your UI, you call .RunWorkerAsync() on the appropriate
BackgroundWorker:
GetLotsOfDataBackgroundWorker.RunWorkerAsync();
ValidateLotsOfTextWorker.RunWorkerAsync(lotsOfText);
The event handler for ValidateLotsOfTextWorker might look like this, calling
your method:
private void ValidateLotsOfTextWorker_DoWork(object sender,
DoWorkEventArgs e) {
string lotsOfText = (string) e.Argument;
e.Result = validateLotsOfText(lotsOfText)
}
When this is done, the worker's RunWorkerCompleted event will fire:
private void ValidateLotsOfTextWorker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e) {
if (e.Error != null) {
// Handle the error
} else {
ValidationResults v = (ValidationResults) e.Result;
// do something with the results
}
}
Now let's say you do the same for LotsOfData, but LotsOfData needs to
validate LotsOfText as part of its operation. Simply call that method
directly from within the DoWork handler:
private void GetLotsOfDataBackgroundWorker_DoWork(object sender,
DoWorkEventArgs e) {
// go to the database and get LotsOfText here
ValidationResults v = validateLotsOfText(lotsOfText);
}
When you want a long-running task done from your UI, use the
BackgroundWorker. If you're already in the background, you don't need to
bother with that and you can simply call methods as you're used to. There's
no need for the *background* task to be responsive, after all.
There's one thing that won't work very well if you do it like this, and
that's progress reporting. If you want your long-running task to report
progress, things get more complicated because you'll want your methods to
call on a BackgroundWorker to do that. But you can't call on just any
BackgroundWorker, because your UI thread might be using it -- you need to
pass the BackgroundWorker to the dependent method. Once you've reached this
point it's probably easier to create BackgroundWorker instances yourself and
not use components. If you don't need to report progress, the above method
will do fine.