ComboBox Items not updated when Collection changes using ObservableCollection

LeoReentry Source

I have ComboBox in a Datagrid that I bind in a .NET WPF application as follows:

<ComboBox x:Name="categoryValues" MinWidth="70" 
          IsSynchronizedWithCurrentItem="False"                   
          SelectedValuePath="Id"
          ItemsSource="{Binding Source={StaticResource categoryViewSource},
                Converter={StaticResource CategoriesToCategoriesConverter}}"
          SelectedItem="{Binding Category,
                Mode=TwoWay,
                UpdateSourceTrigger=PropertyChanged,
                Converter={StaticResource CategoryToCategoryConverter}}"
          DisplayMemberPath="Name" SelectionChanged="categoryValues_SelectionChanged">
</ComboBox>

So each row is bound to the field Category in a different Model. The categoryViewSource is defined as follows

<CollectionViewSource x:Key="categoryViewSource" d:DesignSource="{d:DesignInstance {x:Type Models:Category}, CreateList=True}"/>

My Category Model implements INotifyPropertyChanged using PropertyChanged.Fody NuGet package. After I load the data from the database using Entity Framework, I assign the data to the CollectionViewSource as follow:

var db = new MyDbContext();
System.Windows.Data.CollectionViewSource categoryViewSource = (System.Windows.Data.CollectionViewSource)this.Resources["categoryViewSource"];
await db.Categories.LoadAsync();
categoryViewSource.Source = db.Categories.Local;

So it's bound to the Observable collection. However, once I do

var c = new Category { Name="New Category" };
db.Categories.Add(c);

my CollectionViewSource is updated (at least in the debugger), which seems logical, it's source is an ObservableCollection. But even if I do

categoryViewSource.View.Refresh();

my ComboBox ItemsSource isn't updated. I tried with IsSynchronizedWithCurrentItem="True" as seen somewhere on StackOverflow. So far it only works, if I do something like this:

categoryViewSource.Source = null;
categoryViewSource.Source = db.Categories.Local;

But then my SelectedItem property is null in all ComboBoxes and they appear empty in the Datagrid because apparently the instances of SelectedItem are different once you reassign the collection.

Does anyone have a solution. Unfortunately, I'm still really new to WPF and have no idea.

c#.netwpfxamlcombobox

Answers

answered 1 year ago mm8 #1

Adding a new Category to the DbSet<Category> doesn't affect the ObservableCollection<Category>. These are two different and independent in-memory collections. You will have to add the same object to both Collections.

You could create an ObservableCollection and populate this one with your entity objects when you initialize your ComboBox. And then you add any new objects to both your context and to your data-bound collection, i.e.:

public partial class MainWindow : Window
{
    ObservableCollection<Category> _cats;
    public MainWindow()
    {
        InitializeComponent();

        var db = new MyDbContext();
        System.Windows.Data.CollectionViewSource categoryViewSource = (System.Windows.Data.CollectionViewSource)this.Resources["categoryViewSource"];
        await db.Categories.LoadAsync();
        _cats = new ObservableCollection<Category>(db.Categories.Local);
        categoryViewSource.Source = _cats;
        //...
        var c = new Category { Name = "New Category" };
        db.Categories.Add(c); //add to DbSet
        _cats.Add(c); //add to ObservableCollection
    }
}

Ok, if I add it directly as ItemsSource, that does work. However if I add the collection through a separate Binding, it doesn't work. I need to pass the collection through the converter though. Is there a way to do it automatically?

You could set up the binding programmatically:

categoryValues.SetBinding(ComboBox.ItemsSourceProperty, new Binding(".") { Source = _cats, Converter = new CategoriesToCategoriesConverter() });

comments powered by Disqus