title: How to wait for tasks to finish without blocking the UI
body: <p>this is my first question in this forum and since I'm not a native english speaker I hope you'll go easy on me, in case I'm doing or saying something wrong.</p>
  
  <p>So, here is my question:</p>
  
  <p>I like to solve a simple problem (so it seems), but I'm already researching for over a week and tried different things but none of it worked so far, I always stumbled over the same problem.</p>
  
  <p>What I like to do is opening a progress form, then starting two long running tasks (for instance getting data from two databases). These long running tasks report their progress to the progress form, after they're finished the progress form closes and another form opens to show the results of the two long running tasks. Both tasks have to complete (or cancel/fail) before the progress form closes and the program goes on (or closes).</p>
  
  <p>So, the progress form (Form1) only contains two listboxes (ListBox1 and ListBox2) and the following code:</p>
  
  <pre><code>Public Delegate Sub ShowProgressDelegate(ByVal message As String)
  
  Public Class Form1
  
  Public Sub AddMessage1(ByVal message As String)
    If String.IsNullOrEmpty(message) Then
      Exit Sub
    End If
  
    If Me.InvokeRequired Then
      Me.Invoke(New ShowProgressDelegate(AddressOf Me.AddMessage1), New Object() {message})
    Else
      Me.ListBox1.Items.Add(message)
      Me.ListBox1.SelectedIndex = Me.ListBox1.Items.Count - 1
      Application.DoEvents()
    End If
  End Sub
  
  Public Sub AddMessage2(ByVal message As String)
    If String.IsNullOrEmpty(message) Then
      Exit Sub
    End If
  
    If Me.InvokeRequired Then
      Me.Invoke(New ShowProgressDelegate(AddressOf Me.AddMessage2), New Object() {message})
    Else
      Me.ListBox2.Items.Add(message)
      Me.ListBox2.SelectedIndex = Me.ListBox2.Items.Count - 1
      Application.DoEvents()
    End If
  End Sub
  
  End Class
  </code></pre>
  
  <p>Then I have my TestClass which simulates the long running tasks and raises progress events:</p>
  
  <pre><code>Imports System.Threading
  
  Public Class TestClass
  
    Public Event ShowProgress(ByVal message As String)
  
    Private _milliSeconds As UShort
  
    Public Sub New(milliSeconds As UShort)
      _milliSeconds = milliSeconds
    End Sub
  
    Public Function Run() As UShort
      For i As Integer = 1 To 20
        RaiseEvent ShowProgress("Run " &amp; i)
        Thread.Sleep(_milliSeconds)
      Next i
  
      Return _milliSeconds
    End Function
  
  End Class
  </code></pre>
  
  <p>And finally I have my Main procedure which tries to put these two together:</p>
  
  <pre><code>Imports System.Threading.Tasks
  Imports System.ComponentModel
  
  Public Class Start
    Private Const MULTI_THREAD As Boolean = True
  
    Public Shared Sub Main()
      Dim testClass(1) As TestClass
      Dim testTask(1) As Task(Of UShort)
      Dim result(1) As UShort
  
      testClass(0) = New TestClass(50)
      testClass(1) = New TestClass(100)
  
      Using frm As Form1 = New Form1
        frm.Show()
  
        AddHandler testClass(0).ShowProgress, AddressOf frm.AddMessage1
        AddHandler testClass(1).ShowProgress, AddressOf frm.AddMessage2
  
        If MULTI_THREAD Then
          testTask(0) = Task(Of UShort).Factory.StartNew(Function() testClass(0).Run)
          testTask(1) = Task(Of UShort).Factory.StartNew(Function() testClass(1).Run)
  
          Task.WaitAll(testTask(0), testTask(1))
  
          result(0) = testTask(0).Result
          result(1) = testTask(1).Result
        Else
          result(0) = testClass(0).Run
          result(1) = testClass(1).Run
        End If
  
        RemoveHandler testClass(0).ShowProgress, AddressOf frm.AddMessage1
        RemoveHandler testClass(1).ShowProgress, AddressOf frm.AddMessage2
  
        frm.Close()
      End Using
  
      MessageBox.Show("Result 1: " &amp; result(0) &amp; "; Result 2: " &amp; result(1))
    End Sub
  
  End Class
  </code></pre>
  
  <p>If I set the constant MULTI_THREAD to false, everything works fine (but sequentially). But if I set if to true, it only shows the form, but no progress and it never shows the resulting message box either.
  If I debug it never reaches the line after Task.WaitAll(...).</p>
  
  <p>I already tried other approaches to multi threading like working with plain threads (no return values), backgroundworkers (only percentage progress, no text messages), BeginInvoke/EndInvoke on Delegates, but nothing worked or it showed the same behaviour like described above.</p>
  
  <p>I was told in another forum, that Task.WaitAll blocks the UI-thread since it was called on the UI-thread, but I can't believe that since MSDN clearly states that Task.WaitAll waits for the handed-over tasks to finish or fail and I didn't hand over the UI thread.</p>
  
  <p>So, I don't know what else to try, so I hope you can point out my mistake to me or to show me another way to try to solve my little problem.</p>
  
  <p>Thank you very much in advance.</p>
  
  <p><strong>Update:</strong><br>
  I did a little bit more testing and debugging. If I change the two "Me.Invoke(...)" in the code of my Form to "Me.BeginInvoke(...)" then I still get no progress messages shown in my form, but at least the tasks work and I get my closing message box. So the actual delivering or showing of the progress messages seems to cause the problem.</p>
  
  <p>Maybe this triggers something in your minds?</p>
  
  <p>Thank you again.</p>
  
  <p><strong>Update II:</strong><br>
  After a lot of trial and error it seems to work, at least a little bit. Instead of the "Me.InvokeRequired" parts in the code of my form I handed over "TaskScheduler.FromCurrentSynchronizationContext" when creating the tasks. So I at least got my progress messages shown, but the tasks still don't run completely parallel. But that's a topic for my next question here.</p>