wpfxamldata-bindingcomboboxcompositecollection

Multiple DisplayMemberPaths in a CompositeCollection?


I'm new to WPF. I have a StackPanel which contains multiple comboboxes with the ItemSource (set in the StackPanel's style) from a View (CaSupplierColumns) in SQL Server (Visual Studio created the link automatically which I dragged ordersDataSet from the Data Source panel). No problem with this.

Issue arises when I use CompositeCollection in order to add a custom value to one of the comboboxes (Manufacturer), all values show correctly and the added item appears too - but blank. The added item appears as a blank option in the combobox.

The culprit I discovered is the DisplayMemberPath set to Columns (which is the column header's name in the database view), when I set the DisplayMemberPath to null for this combobox, the added item appears indeed correctly, but the other values in the combobox appear as System.Data.DataRowView.

How can I have two different DisplayMemberPaths in one CompositeCollection? Or perhaps is there a different way to do it?

Here's my current XAML (stripped to leave the key parts):

<Window.Resources>
    <local:OrdersDataSet x:Key="ordersDataSet" />
    <CollectionViewSource x:Key="caSupplierColumnsViewSource" Source="{Binding CaSupplierColumns, Source={StaticResource ordersDataSet}}" />
</Window.Resources>
    <StackPanel Name="MapFields" DataContext="{StaticResource caSupplierColumnsViewSource}">
        <StackPanel.Resources>
            <Style TargetType="ComboBox">
                <Setter Property="ItemsSource" Value="{Binding}" />
                <Setter Property="DisplayMemberPath" Value="Columns" />
                <Setter Property="SelectedValuePath" Value="Columns" />
                <Setter Property="IsSynchronizedWithCurrentItem" Value="False" />
            </Style>
        </StackPanel.Resources>
        ...

        <ComboBox Name="MfrPartNo" />
        ...

        <ComboBox Name="Manufacturer">
            <ComboBox.ItemsSource>
                <CompositeCollection>
                    <CollectionContainer Collection="{Binding Source={StaticResource ResourceKey=caSupplierColumnsViewSource}}" />
                    <ListBoxItem>Another option</ListBoxItem>
                </CompositeCollection>
            </ComboBox.ItemsSource>
        </ComboBox>
    </StackPanel>

Solution

  • I would create implicit DataTemplates for the various types in the collections, and I'd put them in that same StackPanel.Resources where you've got the implicit ComboBox Style. You'll have to get rid of the DisplayMemberPath attribute, because that'll prevent the implicit DataTemplates from being applied.

    DisplayMemberPath isn't a very powerful feature; you switch to DataTemplates when the going gets weird. Throwing a heterogeneous bunch of stuff in a ComboBox is one of the cool things you can do with WPF, but you'll still have to do some work to get much use out of it.

    SelectedValuePath is going to be of limited use here as well, for obvious reasons. You might have to start binding SelectedItem to a viewmodel property of type Object and doing some fiddling in the setter there.

        <StackPanel.Resources>
            <Style TargetType="ComboBox">
                <Setter Property="ItemsSource" Value="{Binding}" />
                <Setter Property="SelectedValuePath" Value="Columns" />
                <Setter Property="IsSynchronizedWithCurrentItem" Value="False" />
            </Style>
    
            <DataTemplate DataType="{x:Type Manufacturer}">
                <!-- I'm assuming Manufacturer has a Name property; change as needed -->
                <TextBlock Text="{Binding Name}" />
            </DataTemplate>
    
            <DataTemplate 
                xmlns:sysdata="clr-namespace:System.Data;assembly=System.Data"
                DataType="{x:Type sysdata:DataRowView}">
                <TextBlock Text="{Binding Columns}" />
            </DataTemplate>
    
            <!-- Etc. -->
    
        </StackPanel.Resources>