title: Adding data to DataSet from different threads and showing them in DataGridView simultaneously
body: <p>I'm trying to add data to <code>DataSet</code> object from 3 different threads. All threads are <code>System.Threading.Timer</code> object threads because I'm using 3 separate timers (<code>System.Threading.Timer</code> type) in the program. After each <code>TimerCallback</code> delegate is invoked I'm acquiring data from some external PLCs (one timer for each PLC) and trying to put those data to <code>DataSet</code>. Acquiring data from PLCs works perfect because I'm able to display these data in some 
  DataGridViews (one DataGridView for each PLC) There is also another<code>DataGridView</code> object (fourth) which should reflect all changes in <code>DataSet</code> immediately because it is bound to the DataSet. In the end these data I would like to put to database - but that's not a problem right now.</p>
  
  <p>I need the data acquired from PLCs to put in the <code>DataSet</code> object. Also what I would like to see is watching all changes from <code>DataSet</code> in <code>DataGridView</code> right away after those changes take place.</p>
  
  <p>I set the (fourth) <code>DataGridView</code> object properties as follows :</p>
  
  <pre><code>this.dgvxDataSet.AutoGenerateColumns = true;
  this.dgvxDataSet.DataSource = DataSet1.Tables[0];
  </code></pre>
  
  <p>My code is as follows :</p>
  
  <pre><code>public partial class Form1 : Form
  {
  
  DataSet _ds = new DataSet("dataSet1");
  System.Threading.Timer timer1;
  System.Threading.Timer timer2;
  System.Threading.Timer timer3;
  
  
  private void Form1_Load(object sender, EventArgs e)
  {
      BuildDataSet();
  
      this.dgvxDataSet.AutoGenerateColumns = true;
      this.dgvxDataSet.DataSource = DataSet1.Tables[0];
  }
  
  private void BuildDataSet()
  { 
      DataTable table1 = DataSet1.Tables.Add("table1");
  
      table1.Columns.Add("col1", typeof(Int32));
      table1.Columns.Add("col2", typeof(Int32));
      table1.Columns.Add("col3", typeof(Int32));
      table1.Columns.Add("col4", typeof(Int32));
      table1.Columns.Add("col5", typeof(DateTime));
      table1.Columns.Add("col6", typeof(Int32));
      table1.Columns.Add("col7", typeof(Int32));
  }    
  
  private void btnReadData_Click(object sender, EventArgs e)
  {
      timer1 = new System.Threading.Timer(new TimerCallback(PoolingStartPLC1), null, 0, Timeout.Infinite);
      timer1.Change(0, (int)nudPollingTiming.Value);
      timer2 = new System.Threading.Timer(new TimerCallback(PoolingStartPLC2), null, 0, Timeout.Infinite);
      timer2.Change(0, (int)nudPollingTiming.Value);
      timer3 = new System.Threading.Timer(new TimerCallback(PoolingStartPLC3), null, 0, Timeout.Infinite);
      timer3.Change(0, (int)nudPollingTiming.Value);            
  }
  
  public void PoolingStartPLC1(object state)
  {
      /*
       Acquireing data from PLC1 which works fine
      */
  
      DataRow newRow;
  
      //I'm adding data to DataSet through MethodInvoker() because the DataSet was created in 
      //the main thread. 
      this.Invoke(new MethodInvoker(() =&gt;
      {
          newRow = DataSet1.Tables[0].NewRow();
          newRow["col1"] = DataSet1.Tables[0].Rows.Count + 1;
          newRow["col2"] = variable11;
          newRow["col3"] = variable12;
          newRow["col4"] = variable13;
          newRow["col5"] = dateTimeVariable1;
      }));
  }
  
  public void PoolingStartPLC2(object state)
  {
      /*
       Acquireing data from PLC2 which works fine
      */
  
      DataRow newRow;
  
      //I'm adding data to DataSet through MethodInvoker() because the DataSet was created in 
      //the main thread. 
      this.Invoke(new MethodInvoker(() =&gt;
      {
          newRow = DataSet1.Tables[0].NewRow();
          newRow["col1"] = DataSet1.Tables[0].Rows.Count + 1;
          newRow["col2"] = variable21;
          newRow["col3"] = variable22;
          newRow["col4"] = variable23;
          newRow["col5"] = dateTimeVariable2;
      }));
  }
  
  public void PoolingStartPLC3(object state)
  {
      /*
       Acquireing data from PLC3 which works fine
      */
  
      DataRow newRow;
  
      //I'm adding data to DataSet through MethodInvoker() because the DataSet was created in 
      //the main thread. 
      this.Invoke(new MethodInvoker(() =&gt;
      {
          newRow = DataSet1.Tables[0].NewRow();
          newRow["col1"] = DataSet1.Tables[0].Rows.Count + 1;
          newRow["col2"] = variable31;
          newRow["col3"] = variable32;
          newRow["col4"] = variable33;
          newRow["col5"] = dateTimeVariable3;
      }));
  }
  
  
  }
  </code></pre>
  
  <p>After a while the data should be in the <code>DataSet</code> object but the problem is they are not. During debugging I see empty <code>DataSet</code> and the <code>DataGridView</code> ofcourse doesn't display any rows ...</p>
  
  <p>I don't know what am i doing wrong. Interestingly I don't receive any concurrency exceptions associated with adding data to the same <code>DataSet</code> object from 3 separate threads simultaneously. Maby I should use some locks or something (if any). If yes - I don't know how and where ... But the worst is that I don't know how put the data (which I have) to <code>DataSet</code>.  </p>
  
  <p>I'm using VS2010 Ultimate. The project is Windows forms project.</p>
  
  <p>Thanks</p>