title: Background Worker: Make sure that ProgressChanged method has finished before executing RunWorkerCompleted
body: <p>Let's assume I'm using a Background Worker and I've the following methods:</p>
  
  <pre><code>private void bw_DoWork(object sender, DoWorkEventArgs e)
  {
      finalData = MyWork(sender as BackgroundWorker, e);
  }
  
  private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
  {
      int i = e.ProgressPercentage; // Missused for i
      Debug.Print("BW Progress Changed Begin, i: " + i + ", ThreadId: " + Thread.CurrentThread.ManagedThreadId);
      // I use this to update a table and an XY-Plot, so that the user can see the progess.
      UpdateGUI(e.UserState as MyData);
      Debug.Print("BW Progress Changed End,   i: " + i + ", ThreadId: " + Thread.CurrentThread.ManagedThreadId);
  }
  
  private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  {
      if ((e.Cancelled == true))
      {
          // Cancelled
      }
      else if (!(e.Error == null))
      {
          MessageBox.Show(e.Error.Message);
      }
      else
      {        
          Debug.Print("BW Run Worker Completed Begin, ThreadId: " + Thread.CurrentThread.ManagedThreadId);
          // I use this to update a table and an XY-Plot, 
          // so that the user can see the final data.
          UpdateGUI(finalData);
          Debug.Print("BW Run Worker Completed End,   ThreadId: " + Thread.CurrentThread.ManagedThreadId);
      }
  }
  </code></pre>
  
  <p>Now I would assume that the <code>bw_ProgressChanged</code> method has finished before the <code>bw_RunWorkerCompleted</code> method is called. But that's not the case and I don't understand why?</p>
  
  <p>I get the following output:</p>
  
  <pre><code>Worker, i: 0, ThreadId: 27
  BW Progress Changed Begin, i: 0, ThreadId: 8
  BW Progress Changed End,   i: 0, ThreadId: 8
  Worker, i: 1, ThreadId: 27
  BW Progress Changed Begin, i: 1, ThreadId: 8
  BW Progress Changed End,   i: 1, ThreadId: 8
  Worker, i: 2, ThreadId: 27
  BW Progress Changed Begin, i: 2, ThreadId: 8
  BW Run Worker Completed Begin, ThreadId: 8
  BW Run Worker Completed End,   ThreadId: 8
  A first chance exception of type 'System.InvalidOperationException' occurred in mscorlib.dll
  ERROR &lt;-- Collection was modified; enumeration operation may not execute.
  ERROR &lt;-- NationalInstruments.UI.WindowsForms.Graph.ClearData()
  </code></pre>
  
  <p>The MagagedID 8 is the <code>Main Thread</code> and 27 is a <code>Worker Thread</code>. I can see this in the Debug / Windows / Threads.</p>
  
  <p>If I don't call <code>UpdateGUI</code> int the <code>bw_ProgressChanged</code> method then no error occurs. But then the user doesn't see any progress in the table and the XY-Plot. </p>
  
  <p><strong>EDIT</strong></p>
  
  <p>The <code>MyWork</code> method looks like that:</p>
  
  <pre><code>public MyData[] MyWork(BackgroundWorker worker, DoWorkEventArgs e)
  {
       MyData[] d = new MyData[n];
       for (int i = 0; i &lt; n; i++) 
           d[i] = null;
       for (int i = 0; i &lt; n; i++)
       {
           if (worker.CancellationPending == true)
           {
               e.Cancel = true;
               break;
           }
           else
           {
               d[i] = MyCollectDataPoint(); // takes about 1 to 10 seconds
               Debug.Print("Worker, i: " + i + ", ThreadId: " + Thread.CurrentThread.ManagedThreadId)
               worker.ReportProgress(i, d);
           }
       }
       return d;
  }
  </code></pre>
  
  <p>and the <code>UpdateGUI</code> method looks like that:</p>
  
  <pre><code>private void UpdateGUI(MyData d)
  {
     UpdateTable(d); // updates a DataGridView
     UpdateGraph(d); // updates a ScatterGraph (NI Measurement Studio 2015)
  }
  </code></pre>
  
  <p>If I don't call <code>UpdateGraph</code> method it works as aspected. So the <code>ProgressChanged</code> method has finished before executing <code>RunWorkerCompleted</code>.</p>
  
  <p>So I guess the problem is the combination of the <code>ScatterGraph</code> from NI Measurement Studio 2015 and the <code>BackgroundWorker</code>. But I don't understand why?</p>
  
  <p>The <code>UpdateGraph</code> method looks like that:</p>
  
  <pre><code>private void UpdateGraph(MyData d)
  {
      plot.ClearData();
      plot.Plots.Clear(); // The error happens here (Collection was modified; enumeration operation may not execute).
      int n = MyGetNFromData(d);        
      for (int i = 0; i &lt; n; i++)
      {
          ScatterPlot s = new ScatterPlot();
          double[] xi = MyGetXiFromData(d, i);
          double[] yi = MyGetYiFromData(d, i);
          s.XAxis = plot.XAxes[0];
          s.YAxis = plot.YAxes[0];
          s.LineWidth = 2;
          s.LineColor = Colors[i % Colors.Length];
          s.ProcessSpecialValues = true;
          s.PlotXY(xi, yi);
          plot.Plots.Add(s);
      }
  }
  </code></pre>
  
  <p><strong>Edit 2</strong></p>
  
  <p>If I set a breakpoint in the <code>bw_RunWorkerCompleted</code> method then the call stack looks like that:</p>
  
  <pre><code>bw_RunWorkerCompleted
  [External Code]
  UpdateGraph // Line: plot.ClearData()
  UpdateGUI
  bw_ProgressChanged
  [External Code]
  Program.Main
  </code></pre>
  
  <p>and the first <code>[External Code]</code> block:</p>
  
  <pre><code>System.dll!System.ComponentModel.BackgroundWorker.OnRunWorkerCompleted(System.ComponentModel.RunWorkerCompletedEventArgs e) Unknown
  [Native to Managed Transition]  
  mscorlib.dll!System.Delegate.DynamicInvokeImpl(object[] args)   Unknown
  System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallbackDo(System.Windows.Forms.Control.ThreadMethodEntry tme) Unknown
  System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(object obj) Unknown
  mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)   Unknown
  mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)   Unknown
  mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) Unknown
  System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallback(System.Windows.Forms.Control.ThreadMethodEntry tme)   Unknown
  System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallbacks()    Unknown
  System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control caller, System.Delegate method, object[] args, bool synchronous) Unknown
  System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke(System.Delegate method, object[] args) Unknown
  System.Windows.Forms.dll!System.Windows.Forms.WindowsFormsSynchronizationContext.Send(System.Threading.SendOrPostCallback d, object state)  Unknown
  NationalInstruments.Common.dll!NationalInstruments.Restricted.CallbackManager.CallbackDispatcher.SynchronousCallbackDispatcher.InvokeWithContext(System.Delegate handler, object sender, System.EventArgs e, System.Threading.SynchronizationContext context, object state) Unknown
  NationalInstruments.Common.dll!NationalInstruments.Restricted.CallbackManager.a(NationalInstruments.Restricted.CallbackManager.CallbackDispatcher A_0, object A_1, object A_2, System.EventArgs A_3)    Unknown
  NationalInstruments.Common.dll!NationalInstruments.Restricted.CallbackManager.RaiseEvent(object eventKey, object sender, System.EventArgs e)    Unknown
  NationalInstruments.Common.dll!NationalInstruments.ComponentBase.RaiseEvent(object eventKey, System.EventArgs e)    Unknown
  NationalInstruments.UI.dll!NationalInstruments.UI.XYCursor.OnAfterMove(NationalInstruments.UI.AfterMoveXYCursorEventArgs e) Unknown
  NationalInstruments.UI.dll!NationalInstruments.UI.XYCursor.a(object A_0, NationalInstruments.Restricted.ControlElementCursorMoveEventArgs A_1)  Unknown
  NationalInstruments.UI.dll!NationalInstruments.UI.Internal.XYCursorElement.OnAfterMove(NationalInstruments.Restricted.ControlElementCursorMoveEventArgs e)  Unknown
  NationalInstruments.UI.dll!NationalInstruments.UI.Internal.XYCursorElement.a(NationalInstruments.UI.Internal.CartesianPlotElement A_0, double A_1, double A_2, int A_3, bool A_4)   Unknown
  NationalInstruments.UI.dll!NationalInstruments.UI.Internal.XYCursorElement.MoveCursorFreely(double xValue, double yValue, bool isInteractive, NationalInstruments.UI.Internal.XYCursorElement.Movement movement)    Unknown
  NationalInstruments.UI.dll!NationalInstruments.UI.Internal.XYCursorElement.MoveCursorXY(double xValue, double yValue, bool isInteractive)   Unknown
  NationalInstruments.UI.dll!NationalInstruments.UI.Internal.XYCursorElement.ResetCursor()    Unknown
  NationalInstruments.UI.dll!NationalInstruments.UI.Internal.XYCursorElement.a(object A_0, NationalInstruments.Restricted.ControlElementEventArgs A_1)    Unknown
  NationalInstruments.UI.dll!NationalInstruments.UI.Internal.PlotElement.OnDataChanged(NationalInstruments.Restricted.ControlElementEventArgs e)  Unknown
  NationalInstruments.UI.dll!NationalInstruments.UI.Internal.PlotElement.OnDataChanged()  Unknown
  NationalInstruments.UI.dll!NationalInstruments.UI.Internal.CartesianPlotElement.a(object A_0, NationalInstruments.UI.Internal.PlotDataChangedEventArgs A_1) Unknown
  NationalInstruments.UI.dll!NationalInstruments.UI.Internal.XYDataManager.a(NationalInstruments.UI.Internal.PlotDataChangedEventArgs A_0)    Unknown
  NationalInstruments.UI.dll!NationalInstruments.UI.Internal.XYDataManager.a(NationalInstruments.UI.Internal.PlotDataChangeCause A_0, int A_1)    Unknown
  NationalInstruments.UI.dll!NationalInstruments.UI.Internal.XYDataManager.ClearData(bool raiseDataChanged)   Unknown
  NationalInstruments.UI.dll!NationalInstruments.UI.Internal.CartesianPlotElement.ClearData(bool raiseDataChanged)    Unknown
  NationalInstruments.UI.dll!NationalInstruments.UI.Internal.PlotElement.ClearData()  Unknown
  NationalInstruments.UI.dll!NationalInstruments.Restricted.XYGraphManager.ClearData()    Unknown
  NationalInstruments.UI.WindowsForms.dll!NationalInstruments.UI.WindowsForms.Graph.ClearData()   Unknown
  </code></pre>