Here’s one thing I have never really understood, apparently… all the time I’ve been using .NET, I’ve been working around this problem somehow. I hope somebody will be able to enlighten me, or maybe we can save the world together by finding a proper approach to this problem. The issue is something that I’m sure most people will have encountered if they program for .NET and they ever use threads — it’s well-known and -documented. Consider the following piece of code:

public partial class Form1 : Form {
  public Form1( ) {
    InitializeComponent( );

    dataGridView1.DataSource = list;
    Thread thread = new Thread(new ThreadStart(ChangeList));
    thread.Start();
  }

  BindingList<DataClass> list = new BindingList<DataClass>();

  public void ChangeList( ) {
    while (true) {
      int numval = list.Count + 1;
      list.Add (new DataClass("Text " + numval, numval));

      Thread.Sleep(1000);
    }
  }
}

public class DataClass {
  public DataClass(string strProp, int intProp) {
    this.strProp = strProp;
    this.intProp = intProp;
  }
  private string strProp;
  public string StrProp {
    get { return strProp; }
    set { strProp = value; }
  }
  private int intProp;
  public int IntProp {
    get { return intProp; }
    set { intProp = value; }
  }
}

I guess a lot of explanation is not necessary, but the short of it is that a list of things is bound to a DataGridView and then updated from a thread. As the update happens from a thread, we have the usual crossing-into-the-UI-thread problem that is the subject of loads of newsgroup questions. Jon explains it very nicely here, so I won’t go into that. In .NET 2, this problem will result in an InvalidOperationException by default, which is a good thing because it doesn’t let you guess what the problem is, as was the case in .NET 1.

Now, my question is: What am I supposed to do about it?

I’ve been browsing the newsgroups for ideas and I was able to find a few threads about this problem, but none of them was able to offer a proper solution, or even a clear analysis of the problem. The piece of advice I usually found was: Make sure you initiate the change notification from the list on the correct (UI) thread. Pardon me, but that is no solution. Why is that no solution? Well, there are a number of reasons:

  • It’s uncomfortable. If I’m using the BindingList<T>, as in the code sample above, there’s really no good place where to write code to check for the “correct” thread.
  • Even if I’m prepared to do the checking, what am I supposed to check against? In any proper OO program, the programmer of the collection class doesn’t know which other objects might bind to the collection’s ListChanged event later on. He also doesn’t know whether these controls are UI controls. This is not because he’s so dumb: he’s really not supposed to know, or to care, or to have to know or care.
  • Even if I found the right place, and was prepared to do the work, and actually had the means to find out which controls were bound to my list, and whether they were UI controls or not, the implementation of such checking code on the collection end of things would be extremely ugly — consider that several bound controls might be running in different UI threads, for instance.
  • Crossing over into the right UI thread (using the standard Invoke/BeginInvoke methods) is a process that involves sending Windows messages internally, which the non-UI thread code would have a hard time participating in.

The only useful conclusion I can come to when I think about this whole weird scenario is: The UI control should do the checking! Let’s see if that would be a problem:

  • The UI control obviously knows which thread it runs on.
  • The UI control knows it has to be careful not to execute any of its own code on the wrong thread — because it knows it’s a UI control (duh!)
  • When the UI control has an event handler method hooked up to an IBindingList’s ListChanged event and that handler method is called from the list, it is extremely easy for the UI control to check whether it’s in the right thread (InvokeRequired) and to change over into the right thread if necessary (Invoke/BeginInvoke).

Given my conclusion and the simplicity of the solution, I can’t help but wonder: Why don’t UI controls do this? Is there something wrong with my way of thinking? Is there an alternative approach I don’t see, with all the same advantages? Or do the programmers of UI controls not know about this problem? Please let me know if you have any thoughts!

Update: I should probably make it clear what controls exactly I’m talking about that don’t adhere to this approach I’m suggesting: the standard Windows Forms controls in the .NET Framework. For instance, I know that the UI controls by Developer Express do use this or a similar approach and are perfectly usable with lists updated in threads.