0

I am trying to bind a combobox in WPF like this,

<ComboBox Width="350" Margin="5" IsEditable="True" ItemsSource="{Binding ComboboxItems}" DisplayMemberPath="Name">

public List<ExpandoObject> ComboboxItems
{
    get
    {
        return comboboxItems;
    }
}

If I set the list like this in my view model,

comboboxItems.Clear();

foreach (ExpandoObject comboboxItem in repository.LoadComboboxItems())
{
    comboboxItems.Add(comboboxItem);
}

NotifyPropertyChanged(this, x => x.ComboboxItems);

The NotifyPropertyChanged seems to work because a breakpoint on the ComboboxItems is hit, but then the combobox list does not update on the GUI. Snoop shows no binding errors or anything like that.

The first time the above list is updated it seems to work, so it can't be anything to do with using an ExpandoObject I don't think.

UPDATE:

Using an observable collection works, but I would like to know if I have a setter in a viewmodel like this which binds to a control on the GUI,

public string Database
{
    get
    {
        return importData.Database;
    }
    set
    {
        importData.Database = value;
        NotifyPropertyChanged(this, x => x.Database);

        comboboxItems.Clear();

        foreach (ExpandoObject comboboxItem in repository.LoadComboboxItems())
        {
            comboboxItems.Add(comboboxItem);
        }

        NotifyPropertyChanged(this, x => x.ComboboxItems);
   }
}

Is that setter being run on a background thread? The reason I ask is will the setter block the GUI if it takes a while to load the items from the database?

This is where I went wrong the first time trying to use an ObservableCollection, by running the code in the setter on a background thread using BackgroundWorker. Updating the ObservableCollection caused an exception under those conditions.

peter
  • 13,009
  • 22
  • 82
  • 142
  • This is the best solution, the extension method AddOnUI http://stackoverflow.com/questions/2091988/how-do-i-update-an-observablecollection-via-a-worker-thread – peter Oct 19 '11 at 22:27
  • The AddOnUI method is a pretty ingenius solution. I modified my BeginInvoke link accordingly. –  Oct 19 '11 at 22:33

2 Answers2

4

I think it will work if you use an ObservableCollection<> instead of a List<>. Unless you use an ObservableCollection, xaml will not know that the contents of the list changed.

To answer the second part of your question, if you're trying to set the ObservableCollection using a BackgroundWorker directly, you will get an exception. One of the ways to get around the exception is to set the ObservableCollection using BeginInvoke

One thing to note: you don't need to call NotifyPropertyChanged(this, x => x.ComboboxItems); in your setter. This is because the property isn't changing; the property is a collection and the collection contents are changing. ObservableCollection will notify subscribers that the contents have changed.

Community
  • 1
  • 1
  • Hmmm. I think you are onto a winner there. I had some other problems with an Observable collection, but see the update because I have rectified most of it. – peter Oct 19 '11 at 21:55
0

Use ObservableCollection instead of the List.

Quoting MSDN:

You can enumerate over any collection that implements the IEnumerable interface. However, to set up dynamic bindings so that insertions or deletions in the collection update the UI automatically, the collection must implement the INotifyCollectionChanged interface. This interface exposes the CollectionChanged event, an event that should be raised whenever the underlying collection changes.

WPF provides the ObservableCollection class, which is a built-in implementation of a data collection that implements the INotifyCollectionChanged interface.

Before implementing your own collection, consider using ObservableCollection or one of the existing collection classes, such as List, Collection, and BindingList, among many others. If you have an advanced scenario and want to implement your own collection, consider using IList, which provides a non-generic collection of objects that can be individually accessed by index. Implementing IList provides the best performance with the data binding engine.

MichaelS
  • 7,023
  • 10
  • 51
  • 75