Reputation: 352
I have a list of URLs and for each URL a BackgroundWorker is created to handle downloading data and updating its respective ProgressBar.
My question is how can I determine when all of the downloads have completed? As of right now, I only can find out when each BackgroundWorker finishes individually but not as a group.
for (int i = 0; i < videos.Count; i++)
{
int index = i;
string path = Path.Combine(Settings.Default.DownloadLocation,
videos[index].Title + videos[index].AudioExtension);
BackgroundWorker worker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = false
};
worker.DoWork += delegate
{
AudioDownloader audioDownloader = new AudioDownloader(videos[index], path);
audioDownloader.AudioExtractionProgressChanged += (obj, args) =>
{
int progress = (int)Math.Round(85 + args.ProgressPercentage * 0.15);
worker.ReportProgress(progress);
};
audioDownloader.DownloadProgressChanged += (obj, args) =>
{
int progress = (int)Math.Round(args.ProgressPercentage * 0.85);
worker.ReportProgress(progress);
};
audioDownloader.Execute();
};
worker.ProgressChanged += (obj, args) =>
{
progressi[index].Value = args.ProgressPercentage;
};
worker.RunWorkerCompleted += delegate
{
Notify(videos[index].Title + " is finished downloading.");
};
worker.RunWorkerAsync();
}
I was considering doing something like this:
Task[] downloadTasks = new Task[videos.Count];
for (int i = 0; i < videos.Count; i++)
{
int index = i;
downloadTasks[index] = Task.Factory.StartNew(() =>
{
// Create BackgroundWorker and run it
});
}
Task.Factory.ContinueWhenAll(downloadTasks, (tasks) =>
{
// All the downloads are complete!
});
But the ContinueWhenAll runs before the downloads are actually complete, so I'm not sure what to do.
Upvotes: 1
Views: 1013
Reputation: 20754
when you are doing this
for (int i = 0; i < videos.Count; i++)
{
int index = i;
downloadTasks[index] = Task.Factory.StartNew(() =>
{
// Create BackgroundWorker and run it
});
}
you create some background worker and tell them to do something in another thread. so just after telling them to do their work your tasks' job is finished so all of them (tasks) will be finished in a moment and
Task.Factory.ContinueWhenAll(downloadTasks, (tasks) =>
{
// All the downloads are complete!
});
checks if all tasks have done their work? the answer is: Yes! they all created a background worker and tell them what to do.
you can use some kind of flags, assign each background worker an Id and set a boolean in an array when it has finished it's work. check if all of them has finished their work and then go on. you can do this in your Notify
method. check if all of the flags are true and then do what you want there.
Upvotes: 2
Reputation: 1159
Another simple workaround - use a counter that keeps track of all your backgroundworkers.
int counter = 0;
In the DoWork of each backgroundworker:
private void bwDoWork(object sender, DoWorkEventArgs e)
{
Interlocked.Increment(ref counter);
//do other stuff
}
and in each RunWorkerCompleted, decrement the counter and check if zero, which tells you that all backgroundworkers are done
private void bwRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Interlocked.Decrement(ref counter);
if (counter == 0)
{
//All backgroundworkers are done, so do something
}
}
Upvotes: 1
Reputation: 2273
Using a BackgroundWorker is somewhat outdated since .Net 4.5 by task-returning async methods. This is nicely explained why here.
In your use case, you would probably end up with something as simple as:
public async Task DownloadTask()
{
Task[] tasks = new Task[2];
tasks[0] = DoSomeStuff();
tasks[1] = DoSomeStuff();
await Task.WhenAll(tasks);
}
Upvotes: 1