WPF BackgroundWorker Execution
I've been programming C# for a while now (I'm a Computer Science major), and have never had to implement threading.
I am currently building an application for a client that requires threading for a series of operations.
Due to the nature of the client/provider agreement, I cannot release the source I am working with. The code 开发者_如何转开发that I have posted is in a general form. Pretty much the basic idea of what I am implementing, excluding the content specific source.
The first Snippet demonstrates my basic structure,
The Progress class is a custom progress window that is displayed as a dialog to prevent user UI interaction.
I am currently using the code to complete database calls based on a collection of objects in another area of the application code.
For example, I have a collection of "Objects" of one of my custom classes, that I perform these database calls on or on behalf of. My current set up works just fine when I call the "GeneralizedFunction" one and only one time.
What I need to do is call this function once for every object in the collection. I was attempting to use a foreach loop to iterate through the collection, then I tried a for loop.
For both loops, the result was the same. The Async operation performs exactly as desired for the first item in the collection. This, however, is the only one it works for. For each subsequent item, the progress box (my custom window) displays and immediately closes.
In terms of the database calls, the calls for the first item in the collection are the only ones that successfully complete. All others aren't attempted.
I've tried everything that I know and don't know to do, but I just cannot seem to get it to work.
How can I get this to work for my entire collection?
Any and all help is very greatly appreciated.
Progress progress;
BackgroundWorker worker;
// Cancel the current process
private void CancelProcess(object sender, EventArgs e)
{
worker.CancelAsync();
}
// The main process ... "Generalized"
private void GeneralizedFunction()
{
progress = new Progress();
progress.Cancel += CancelProcess;
progress.Owner = this;
Dispatcher pDispatcher = progress.Dispatcher;
worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
object[] workArgs = { arg1, arg2, arg3};
worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
/* All main logic here
*/
foreach(Class ClassObject in ClassObjectCollection)
{
//Some more logic here
UpdateProgressDelegate update = new UpdateProgressDelegate(updateProgress);
pDispatcher.BeginInvoke(update, arg1,arg2,arg3);
Thread.Sleep(1000);
}
};
worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{
progress.Close();
};
worker.RunWorkerAsync(workArgs);
progress.ShowDialog();
}
public delegate void UpdateProgressDelegate(arg1,arg2,arg3);
private void updateProgress(arg1,arg2,arg3)
{
//Update progress
}
OK, so you have a background process running in the DoWork handler. That thread spawns a number of other threads (with BeginInvoke) and then sleeps 1 sec. (why the Sleep(1000) ?)
There seems to be no attempt to wait for the UpdateProgressDelegate threads to finish after the for loop. So you will be calling progress.Close();
when some of those pDispatchers are still executing.
I also can't see any communication between the Bgw and the Dialog.
The quick fix here would be not to call BeginInvoke inside the loop but execute all logic in 1 the bgw thread. First make it work. And a tip: real programs don't Sleep()
And then, if you want to spawn more threads, you need to implement some rendez-vous logic. With an EventWaitHandle class or something.
Note that this becomes a whole lot easier in .NET 4 (with Parallel.ForEach)
Set a breakpoint on progress.Close()
to see if it is being called (causing the progress window to vanish). You probably need to call DispatcherOperation.Wait()
to ensure that the DoWork() doesn't exit until all ASYNC work is entirely completed. BeginInvoke() returns the DispatcherOperation - you need to use it to join the threads and wait for them to complete.
You probably need to keep a list of all invoked DispatherOperations (pDispatcher.BeginInvoke(update, arg1,arg2,arg3)). After the foreach loop, you just wait for each one to complete. I assume the issue is that RunWorkerCompleted is firing since you aren't waiting for the DispatchOperation to finish (thus closing the progress window).
精彩评论