locked
Task.WhenAll Not Working

    Question

  • I have several tasks which involve binding collections to ItemsCollections for which I want to do concurrently using Task.WhenAll (or whatever the appropriate method is, if I am wrong). My current code is:
    Private Async Function BindAll() As Task
    	System.Diagnostics.Debug.WriteLine("BindAll - Start")
    	Dim bindingtasks As New List(Of Task)
    	If Me.chkDisplayRound.IsChecked Then bindingtasks.Add(New Task(AddressOf Me.BindRoundNumbers))
    	If Me.players IsNot Nothing AndAlso Me.players.Any Then
    		bindingtasks.Add(New Task(AddressOf Me.BindNames))
    		bindingtasks.Add(New Task(AddressOf Me.BindScores))
    		If Me.radCumulative.IsChecked Then bindingtasks.Add(New Task(AddressOf Me.BindTotals))
    		System.Diagnostics.Debug.WriteLine("BindAll - Checkpoint 1")
    		Await Task.WhenAll(bindingtasks)
    		System.Diagnostics.Debug.WriteLine("BindAll - Checkpoint 2")
    		'Scroll to make the current score visible
    		Await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Sub() Me.scrScores.ScrollToRequired(Me.GetRequiredVisible()))
    		Me.stkEnterNames.Visibility = Visibility.Collapsed
    	Else : Me.stkEnterNames.Visibility = Visibility.Visible
    	End If
    	System.Diagnostics.Debug.WriteLine("BindAll - End")
    End Function
    

    My code locks up at Await Task.WhenAll(bindingtasks) (between Checkpoint 1 and Checkpoint 2). If I call the methods that I am making into Tasks (BindRoundNumbers(), BindNames(), BindScores(), and BindTotals()) individually, everything is fine, but I want to call them concurrently. What am I doing wrong? Thanks.

    Nathan Sokalski njsokalski@hotmail.com http://www.nathansokalski.com/

    Wednesday, August 20, 2014 2:39 AM

Answers

  • You should use the Task.Run or TaskFactory.StartNew methods when you create a new task and not the Task constructor. Using any of these metods to create a task will start the task immediately after it has been created:

        Private Async Function BindAll() As Task
            System.Diagnostics.Debug.WriteLine("BindAll - Start")
            Dim bindingtasks As New List(Of Task)
            If Me.chkDisplayRound.IsChecked Then bindingtasks.Add(Task.Run(AddressOf Me.BindRoundNumbers))
    
            If Me.players IsNot Nothing AndAlso Me.players.Any Then
                bindingtasks.Add(Task.Run(AddressOf Me.BindNames))
                bindingtasks.Add(Task.Run(AddressOf Me.BindScores))
                If Me.radCumulative.IsChecked Then bindingtasks.Add(Task.Run(AddressOf Me.BindTotals))
                System.Diagnostics.Debug.WriteLine("BindAll - Checkpoint 1")
                Await Task.WhenAll(bindingtasks)
                System.Diagnostics.Debug.WriteLine("BindAll - Checkpoint 2")
                'Scroll to make the current score visible
                Await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Sub() Me.scrScores.ScrollToRequired(Me.GetRequiredVisible()))
                Me.stkEnterNames.Visibility = Visibility.Collapsed
            Else : Me.stkEnterNames.Visibility = Visibility.Visible
            End If
            System.Diagnostics.Debug.WriteLine("BindAll - End")
        End Function
    

    Thursday, August 21, 2014 12:32 PM

All replies

  • Hi Nathan,

    While you bind those tasks into bindingtask collection, have you call the Task.Start() method? 

    For Each task As var In tasks
         task.Start()
    Next
    

    Or you can use Task.Factory.StartNew to initialize a task and run it immediately. See this for more information: StartNew Method (Action), then you could use the following code to deal with the result.

                await Task.Factory.ContinueWhenAll(tasks.ToArray(), continueworks =>
                {
                    //do somthing to the reuslt
                    foreach (var work in continueworks)
                    {
                        int result = work.Result;
                    }
                });

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Thursday, August 21, 2014 11:20 AM
    Moderator
  • You should use the Task.Run or TaskFactory.StartNew methods when you create a new task and not the Task constructor. Using any of these metods to create a task will start the task immediately after it has been created:

        Private Async Function BindAll() As Task
            System.Diagnostics.Debug.WriteLine("BindAll - Start")
            Dim bindingtasks As New List(Of Task)
            If Me.chkDisplayRound.IsChecked Then bindingtasks.Add(Task.Run(AddressOf Me.BindRoundNumbers))
    
            If Me.players IsNot Nothing AndAlso Me.players.Any Then
                bindingtasks.Add(Task.Run(AddressOf Me.BindNames))
                bindingtasks.Add(Task.Run(AddressOf Me.BindScores))
                If Me.radCumulative.IsChecked Then bindingtasks.Add(Task.Run(AddressOf Me.BindTotals))
                System.Diagnostics.Debug.WriteLine("BindAll - Checkpoint 1")
                Await Task.WhenAll(bindingtasks)
                System.Diagnostics.Debug.WriteLine("BindAll - Checkpoint 2")
                'Scroll to make the current score visible
                Await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Sub() Me.scrScores.ScrollToRequired(Me.GetRequiredVisible()))
                Me.stkEnterNames.Visibility = Visibility.Collapsed
            Else : Me.stkEnterNames.Visibility = Visibility.Visible
            End If
            System.Diagnostics.Debug.WriteLine("BindAll - End")
        End Function
    

    Thursday, August 21, 2014 12:32 PM