title: How do I safely populate with data and Refresh() a DataGridView in a multi-threaded application?
body: <p>My app has a DataGridView object and a List of type MousePos. MousePos is a custom class that holds mouse X,Y coordinates (of type "Point") and a running count of this position. I have a thread (System.Timers.Timer) that raises an event once every second, checks the mouse position, adds and/or updates the count of the mouse position on this List.</p>
  
  <p>I would like to have a similar running thread (again, I think System.Timers.Timer is a good choice) which would again raise an event once a second to automatically Refresh() the DataGridView so that the user can see the data on the screen update. (like TaskManager does.)</p>
  
  <p>Unfortunately, calling the DataGridView.Refresh() method results in VS2005 stopping execution and noting that I've run into a cross-threading situation.</p>
  
  <p>If I'm understanding correctly, I have 3 threads now:</p>
  
  <ul>
  <li>Primary UI thread</li>
  <li>MousePos List thread (Timer)</li>
  <li>DataGridView Refresh thread (Timer)</li>
  </ul>
  
  <p>To see if I could Refresh() the DataGridView on the primary thread, I added a button to the form which called DataGridView.Refresh(), but this (strangely) didn't do anything. I found a topic which seemed to indicate that if I set DataGridView.DataSource = null and back to my List, that it would refresh the datagrid. And indeed this worked, but only thru the button (which gets handled on the primary thread.)</p>
  
  <hr>
  
  <p>So this question has turned into a two-parter:</p>
  
  <ol>
  <li>Is setting DataGridView.DataSource to null and back to my List an acceptable way to refresh the datagrid?  (It seems inefficient to me...)</li>
  <li>How do I safely do this in a multi-threaded environment?</li>
  </ol>
  
  <hr>
  
  <p>Here's the code I've written so far (C#/.Net 2.0)</p>
  
  <pre><code>public partial class Form1 : Form
  {
      private static List&lt;MousePos&gt; mousePositionList = new List&lt;MousePos&gt;();
      private static System.Timers.Timer mouseCheck = new System.Timers.Timer(1000);
      private static System.Timers.Timer refreshWindow = new System.Timers.Timer(1000);
  
      public Form1()
      {
          InitializeComponent();
          mousePositionList.Add(new MousePos());  // ANSWER! Must have at least 1 entry before binding to DataSource
          dataGridView1.DataSource = mousePositionList;
          mouseCheck.Elapsed += new System.Timers.ElapsedEventHandler(mouseCheck_Elapsed);
          mouseCheck.Start();
          refreshWindow.Elapsed += new System.Timers.ElapsedEventHandler(refreshWindow_Elapsed);
          refreshWindow.Start();
      }
  
      public void mouseCheck_Elapsed(object source, EventArgs e)
      {
          Point mPnt = Control.MousePosition;
          MousePos mPos = mousePositionList.Find(ByPoint(mPnt));
          if (mPos == null) { mousePositionList.Add(new MousePos(mPnt)); }
          else { mPos.Count++; }
      }
  
      public void refreshWindow_Elapsed(object source, EventArgs e)
      {
          //dataGridView1.DataSource = null;               // Old way
          //dataGridView1.DataSource = mousePositionList;  // Old way
          dataGridView1.Invalidate();                      // &lt;= ANSWER!!
      }
  
      private static Predicate&lt;MousePos&gt; ByPoint(Point pnt)
      {
          return delegate(MousePos mPos) { return (mPos.Pnt == pnt); };
      }
  }
  
  public class MousePos
  {
      private Point position = new Point();
      private int count = 1;
  
      public Point Pnt { get { return position; } }
      public int X { get { return position.X; } set { position.X = value; } }
      public int Y { get { return position.Y; } set { position.Y = value; } }
      public int Count { get { return count; } set { count = value; } }
  
      public MousePos() { }
      public MousePos(Point mouse) { position = mouse; }
  }
  </code></pre>