I run about 50 tasks (Task). Tasks are performed at different speeds.

I need to display the number of running tasks in WPF control .

As I understand it, there should be a counter that ++ at the start of the task, and -- at the completion of the task. As soon as the counter becomes == 0 , you need to call a specific method.

In theory, such a scenario should have a ready-made solution, but did not find anything suitable. The only thing that comes to mind is to make the counter int count = 0; and object countLock = new Object(); and change the value of count from different tasks like this lock(countLock) count++; . But it seems to me that there is a better solution?

Note: tasks are not started all at once, but by queues. A few started, a pause, a few more started, a pause. At this time, some of the tasks may be completed, and a few more run.

  • one
    like whenAll - does that work? - Grundy
  • And how from WhenAll to display the number of remaining tasks on the screen? - Box

2 answers 2

For example, so.

 List<Task> tasks = // ваши 50 task'ов RemainingTasks = tasks.Count; List<Task> augmentedTasks = tasks.Select(async t => { await t; RemainingTasks--; }).ToList(); await Task.WhenAll(augmentedTasks); // здесь все 50 завершились 

(Of course, this should be in the async method, and be run in the UI thread.)

If RemainingTasks is a property in a VM with INotifyPropertyChanged , you can bind to it in the UI. Well, or if for some reason you are not yet using MVVM, and you are doing everything in OnClick (horror of horrors!), You can start a dependency property.


If your tasks are added in batches, then you need to change the counter in batches.

 async Task CreateTasks() { List<Task> tasks = // создаёте здесь новые Task'и как вам хочется RemainingTasks += tasks.Count; List<Task> augmentedTasks = tasks.Select(async t => { await t; RemainingTasks--; }).ToList(); await Task.WhenAll(augmentedTasks); // здесь все *добавленные* Task'и отработали, и вы можете сделать // что-то ещё. но может быть, что тем временем другой вызов CreateTasks() // создал ещё, так что в этой точке RemainingTasks не обязательно 0 } 
  • Comments are not intended for extended discussion; conversation moved to chat . - PashaPash

Keep:

 public class BackgroundTaskManager : GalaSoft.MvvmLight.ViewModelBase { private int activeTasks; public int ActiveTasks { get { return activeTasks; } set { base.Set("ActiveTasks", ref activeTasks, value) } } public IDisposable StartTask() { ActiveTasks++; return new TaskToken(this); } private class TaskToken : IDisposable { private readonly BackgroundTaskManager owner; public TaskToken(BackgroundTaskManager owner) { this.owner = owner; } public void Dispose() { owner.ActiveTasks--; } } } 

Using:

 async void SomeAction() { using (bgtm.StartTask()) { await ...; } } 

This method counts the tasks prepared for counting that are created in the UI thread. In an amicable way, we must also add Asserts, but I forgot how to check that the current thread is a UI stream.

  • Can I use GalaSoft and where can I get this class? - Box
  • In the corresponding package nuget - Pavel Mayorov
  • How correct is it not to follow the Dispose pattern, which is given in the msdn.microsoft.com/en-us/library/b1yfkh5e (v = vs.110 ).aspx documentation ? Do I need to add code from the Basic Dispose Pattern or can I leave it as a response? - Box
  • No, don't. It is even impossible. In this case, everything is built on the fact that access to the ActiveTasks property ActiveTasks always come from the same flow - but for the finalizer this rule will be broken. - Pavel Mayorov