locked
WPF Data binding and thread safety RRS feed

  • Question

  • When binding to a collection as an ItemsSource, do I have to worry about thread safety?

    In other words, I have a listbox, defined in XAML.

    In the code, I have

    //somewhere in global variables

    List<myClass> myListOfStuff;

    In the XAML:

    <ListBox Name="mylistbox">

    <ListBox.ItemTemplate>

        <DataTemplate>

            <TextBlock Text={Binding Path=myProperty}>

        </ etc....... 

    In the codebehind of my XAML

    void somefunction()

    {

    mylistbox.ItemsSource=Globals.MyListOfStuff;

    }

    So, I open up my window with the list box in it, and at some point I trigger somefunction, which binds the itemsSource to a global list.  In the Item template for the list box, it has a text block bound to a property of myClass, so what I want is to see one line with that property for each item in the list.

    I'm guessing that in order to display those values, it has to iterate through the list.

    If that list is accessed by multiple threads, what happens if one of those other threads adds a new element to the list at about the same time that something on my XAML page is causing the somefunction to execute?  Is there any way to lock the object during that access?  Which piece of code would I lock, anyway?  Or does some sort of lock happen by magic?

    Friday, September 27, 2013 7:34 PM

Answers

  • "That makes sense.....except that I'm not doing any processing."

    Processing or not such code doesn't make any sense whatsoever. A ListBox is a WPF control and as such it can only be accessed by a single thread, the thread that created it. There's no such thing as "other thread accessing this listbox simultaneously" because any such attempt would result in an exception, with or without that lock.

    "Or is it that if a WPF control that has items in it cannot be bound to any collection that might be modified in a different thread, so all modifications to the list or other collection has to be marshalled to the UI thread?"

    Pretty much. It's possible that adding items to a List<T> actually works fine if the list is bound to a WPF ItemsControl because WPF tends to access the list via the indexer rather than using the enumerator. Still, there's no guarantee that it will work correctly in all circumstances.

    • Marked as answer by David Lame Monday, September 30, 2013 1:55 PM
    Monday, September 30, 2013 1:21 PM

All replies

  • WPF or not, List<T> is not thread safe, you can't safely modify it from a thread if other threads are reading/modifying it. You can, however, read it from multiple threads.

    Note that List<T> doesn't raise any change notifications so adding something to the list after the list was bound to an items control won't change the UI. You need to use a ObservableCollection<T> for that to happen. If you do use a ObservableCollection you'll notice that WPF will throw an exception if you try to modify the collection from a background thread.

    The usual solution is to forward collection changes to the UI thread via a Dispatcher.BeginInvoke call. This way the list is always modified and at least the WPF issue is avoided. Even so you may still need to use a lock if there are other threads that can read the list while the UI thread is modifying it, again, this isn't WPF specific.

    WPF 4.5 has a feature that allows you to modify collections from background threads: http://10rem.net/blog/2012/01/20/wpf-45-cross-thread-collection-synchronization-redux

    Saturday, September 28, 2013 4:41 AM
  • I'm guessing that in order to display those values, it has to iterate through the list.

    If that list is accessed by multiple threads, what happens if one of those other threads adds a new element to the list at about the same time that something on my XAML page is causing the somefunction to execute? 

    Likely it'll raise an exception if the iteration is an foreach loop or uses the enumerator.
    List<T> has its own internal "version" flag, that is incremented anytime the list is changed (by adding, removing, moving one or multiple items).

    While an iteration is going on, as soon as the version is different from the one the iteration started with, an InvalidOperationException is thrown. Maybe the WPF controls are aware of this problem and lock the collections they deals with by using their implementation of the ICollection.SyncRoot property, which is meant to synchronize collection access.


    Monday, September 30, 2013 12:34 AM
  • "Maybe the WPF controls are aware of this problem and lock the collections they deals with by using their implementation of the ICollection.SyncRoot property"

    Nope, in general WPF assumes that everything happens in the UI thread. Besides, ICollection.SyncRoot is kind of obsolete, you'll find very few uses of it throughout the framework.

    Monday, September 30, 2013 6:23 AM
  • Yes you need to lock the listbox object and do what ever processing you want to do on that. for that you can do in following way.

    lock(mylistbox)
    {
    do processing here..
    ...
    ...
    
    }

    in the abvoe code block, all the execution statements with in the block are accessable for only one thread at a time. so that you need not bother about other thread accessing this listbox simulatenously.

    apart from this you can consider other ways of thread synchronizing methods also like using Mutex, Monitor classes also as per your scenario and requirement. 

    Monday, September 30, 2013 6:58 AM
  • Yes you need to lock the listbox object and do what ever processing you want to do on that. for that you can do in following way.

    lock(mylistbox)
    {
    do processing here..
    ...
    ...
    
    }

    in the abvoe code block, all the execution statements with in the block are accessable for only one thread at a time. so that you need not bother about other thread accessing this listbox simulatenously.

    apart from this you can consider other ways of thread synchronizing methods also like using Mutex, Monitor classes also as per your scenario and requirement. 

    That makes sense.....except that I'm not doing any processing.  WPF is doing it for me, and I don't know where to lock it.

    What's happening is that I have a listbox, and I say myListBox.ItemsSource= Globals.myList.

    Meanwhile, over in the other thread, I have Globals.myList.Add(new thing());

    I know that I cannot add a new thing to a list while I am iterating through the list.  What I don't know is when I'm iterating through the list.  I know it has to happen at some point, but I don't know when, so I don't know what to lock.

    Or is it that if a WPF control that has items in it cannot be bound to any collection that might be modified in a different thread, so all modifications to the list or other collection has to be marshalled to the UI thread?

    Monday, September 30, 2013 1:00 PM
  • "That makes sense.....except that I'm not doing any processing."

    Processing or not such code doesn't make any sense whatsoever. A ListBox is a WPF control and as such it can only be accessed by a single thread, the thread that created it. There's no such thing as "other thread accessing this listbox simultaneously" because any such attempt would result in an exception, with or without that lock.

    "Or is it that if a WPF control that has items in it cannot be bound to any collection that might be modified in a different thread, so all modifications to the list or other collection has to be marshalled to the UI thread?"

    Pretty much. It's possible that adding items to a List<T> actually works fine if the list is bound to a WPF ItemsControl because WPF tends to access the list via the indexer rather than using the enumerator. Still, there's no guarantee that it will work correctly in all circumstances.

    • Marked as answer by David Lame Monday, September 30, 2013 1:55 PM
    Monday, September 30, 2013 1:21 PM