Updating a list from a thread – the UI control should do the checking

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.

7 Comments on Updating a list from a thread – the UI control should do the checking

  1. John Gooding // July 21, 2006 at 5:46 pm // Reply

    I think the real issue is that BindingList isn’t thread safe :)I found an article that has similar code to what I use http://www.windowsforms.net/articles/asyncbindinglist.aspx in your sample it will throw a null reference or thread error on exit only because there is no thread join / clean exit for the background thread.Hope that helps.John

    Like

  2. This problem doesn’t have anything to do with the binding list being thread safe or not, as the list is only updated from one thread. You are right that my sample doesn’t end the thread in any way – that’s because it’s a sample 🙂 But the exception in question is triggered not on program exit, but rather after the very first update to the collection.Anyway, this is all not the problem – I understand every tiny little bit about the original problem (and the solution) of synching into the UI thread. The thing I’m talking about is that if things are left to me as the programmer of a collection class (instead of the UI control programmer handling things), there’s really no way for me to do the job correctly, because the UI thread is simply something I’m not concerned with.

    Like

  3. That’s an interesting post you are pointing to, but it tries to find a way to work with the broken architecture in standard Windows Forms (in this regard, of course) instead of proposing a solution to fix the breakage. The approach seems to introduce an enormous overhead and it has the requirement of instantiating the collections in the UI thread, which I think can be pretty difficult to comply with in real-world applications (or libraries/frameworks, even worse). I’m sure it would be a great deal easier to simply let the UI control itself do the work – after all, the requirement to run on the UI thread is a requirement introduced by the UI control in the first place, so it should have the responsibility of assuring that this is adhered to. Not to mention it’s simply the easiest way.And finally, I can’t imagine Microsoft made their decision to NOT do this in their UI controls because they knew this Daniel guy would come up with his idea 🙂 I’m not much closer to understanding why MS (specifically, but probably loads of other component writers) decided to go the way they did.Hey, thanks for your comment – I certainly appreciate the pointer!

    Like

  4. Kenneth E. // July 29, 2006 at 2:37 pm // Reply

    Well, I think this problem is not exactly introduced by .net, as it’s a lot older than .net itself :-)The problem has always tricked developers to do all kinds of weird workarounds in order to avoid synchronization issues between threads and especially the UI. If we look aside from all those kind of "spooky" workarounds I’ve made through time, I finally found a way that *always* works, and at the same time is extremely simple…Use Timer(s) on the form to do all updates and get (synchonize) all "external" data from other processes and threads. The timer will always execute in the GUI thread, and there’s no circular events which in turns feed themself and so on. Always clear, clean and simple.You can probably do more exact timing in your GUI by calling directly into (or triggering) it from external threads and so on, but you pay a high price in increased complexity (and sometimes performance as well). So let the UI handle all UI tasks and let it also decide when and how often to update itself. Ofcourse you should ensure all means of thread safety required when reading from the "external" data sources.I’ve done a fair amoung of thread development over time, and as simple this "design" may look, as much I love it for saving my time and solving all those weird, and sometimes almost impossible to find bugs that comes along with a complex design involving synchronization between 30+ threads.In other words, don’t trigger or call into the UI from your external threads. This way you always knows who is in control at any time, as many synchronization/thread issues is actually about who has responsability at which point in time.

    Like

  5. Andrew Gruskin // August 20, 2006 at 9:54 am // Reply

    I am trying an idea loosely based around "The UI control should do the checking". Instead it’s more of a "The UI control should register it existence to the IBindingList".First, I’ve done passing a reference of the UI control to the IBindingList instance but that is bad as it does couple my UI too much to the data layer.Instead the UI registers itself to a helper class. The IBindingList class checks the helper to see if a UI control exists and if so calls update on the UI thread.This solution is neater, to me, as my data layer "engine" may be in a UI application. If so, then the IBindingList doesn’t find a registered UI control (and thread) to update on.(And I am using XtraGrid, but I’m sure that’s unimportant).

    Like

  6. Oliver, I completely agree with you 100%. What a stupid decision on Microsoft’s part not to handle this issue in the OnUpdateMethod of the DataGridView.I too am looking for a proper solution to this problem, and thus far the best I have found is similar to Kenneth’s suggestion to use Timers. However, you are going to want to write code on your form which listens to the ListUpdate event and enable the timer only then, disabling it in the timer_OnTick method so that you are not letting the timer call the UI thread for no reason. In addition, you’ll want to keep track of which rows have changed, and only force the UI to update those rows or if add/deletes have occured, refresh the entire grid.In actuality, this creates a more streamlined GUI than if you have to Invoke over to the GUI every time a single cell changes.Anyway, please let me know if you have come to any further conclusions about this issue.-Eric

    Like

  7. The solution at http://www.windowsforms.net/articles/asyncbindinglist.aspx involves a dependency upon System.Windows.Forms that I’d rather not have in my data assembly. I’d propose an alternative solution that wraps an existing IBindingList (takes it in the constructor) and marshalls the events across the thread boundary in the wrapper.In the end I just went with a 3rd party control though 🙂

    Like

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s