Search code examples
wpfxamldata-bindingcomboboxcompositecollection

Adding custom values to ComboBox with CompositeCollection


I'm new to WPF. I have a combobox which when choosing a value three other fields (AbbrBlock, MultiBrandSupplier, IgnoreNoCompetition) update along to show the correct relevant values according to the data source. No problem with this.

Issue arises when I try to add to the combobox a custom value, although the combobox shows all values correctly, the other fields don't change when changing the combobox's value.

Here's the working code (without the additional custom combobox value - stripped to the key pieces):

<Window.Resources>
    <local:OrdersDataSet x:Key="ordersDataSet" />
    <CollectionViewSource x:Key="caSuppliersViewSource" Source="{Binding CaSuppliers, Source={StaticResource ordersDataSet}}"/>
</Window.Resources>

...

<StackPanel DataContext="{StaticResource caSuppliersViewSource}">
    <ComboBox Name="SupplierDropdown" DisplayMemberPath="SupplierName" 
        ItemsSource="{Binding Source={StaticResource ResourceKey=caSuppliersViewSource}}"/>
    <TextBlock Name="AbbrBlock" VerticalAlignment="Center" Text="{Binding Abbr}"/>
    <CheckBox Name="MultiBrandSupplier" IsChecked="{Binding MultiBrand}"/>
    <CheckBox Name="IgnoreNoCompetition" IsChecked="{Binding IgnoreNoCompetition}"/>
</StackPanel>

Here's the code with the added custom value which shows correctly but the other fields don't update when changing the combobox value:

<Window.Resources>
    <local:OrdersDataSet x:Key="ordersDataSet" />
    <CollectionViewSource x:Key="caSuppliersViewSource" Source="{Binding CaSuppliers, Source={StaticResource ordersDataSet}}"/>
</Window.Resources>

...

<StackPanel DataContext="{StaticResource caSuppliersViewSource}">
    <StackPanel.Resources>
        <CompositeCollection x:Key="myCompositeCollection">
            <CollectionContainer Collection="{Binding Source={StaticResource ResourceKey=caSuppliersViewSource}}" />
            <ComboBoxItem Content="Add New..." />
        </CompositeCollection>
    </StackPanel.Resources>
    <ComboBox Name="SupplierDropdown" DisplayMemberPath="SupplierName" 
        ItemsSource="{Binding Source={StaticResource myCompositeCollection}}"/>
    <TextBlock Name="AbbrBlock" VerticalAlignment="Center" Text="{Binding Abbr}"/>
    <CheckBox Name="MultiBrandSupplier" IsChecked="{Binding MultiBrand}"/>
    <CheckBox Name="IgnoreNoCompetition" IsChecked="{Binding IgnoreNoCompetition}"/>
</StackPanel>

What am I missing here?


Solution

  • Looks like the ComboBox was updating caSuppliersViewSource's View.CurrentItem property (I think) to match its SelectedItem in your first snippet. In the second, the CollectionViewSource is buried inside a CompositeCollection so that doesn't happen any more. However, the ComboBox is still selecting an item, and you can just bind to that using ElementName. No need for setting the DataContext on the StackPanel with this version.

    <StackPanel>
        <StackPanel.Resources>
            <CompositeCollection x:Key="myCompositeCollection">
                <CollectionContainer Collection="{Binding Source={StaticResource ResourceKey=caSuppliersViewSource}}" />
                <ComboBoxItem Content="Add New..." />
            </CompositeCollection>
        </StackPanel.Resources>
        <ComboBox 
            Name="SupplierDropdown" 
            DisplayMemberPath="SupplierName" 
            ItemsSource="{Binding Source={StaticResource myCompositeCollection}}"
            />
        <TextBlock 
            Name="AbbrBlock" 
            VerticalAlignment="Center" 
            Text="{Binding SelectedItem.Abbr, ElementName=SupplierDropdown}"
            />
        <CheckBox 
            Name="MultiBrandSupplier" 
            IsChecked="{Binding SelectedItem.MultiBrand, ElementName=SupplierDropdown}"
            />
        <CheckBox 
            Name="IgnoreNoCompetition" 
            IsChecked="{Binding SelectedItem.IgnoreNoCompetition, ElementName=SupplierDropdown}"
            />
    </StackPanel>
    

    You could also give eyour viewmodel a SelectedDBItem property of the same type as whatever caSuppliersViewSource contains, and bind ComboBox.SelectedItem to that. Then you could do this:

        <TextBlock 
            Name="AbbrBlock" 
            VerticalAlignment="Center" 
            Text="{Binding SelectedDBItem}"
            />
    

    But that's six dozen of one, half of another, or something -- unless you want to do something else with SelectedDBItem in your viewmodel, then it's handy.