wpfdata-bindingcomboboxdatagridcompositecollection

In a datagrid, how do you bind a different ItemsSource for each row when also using a CompositeCollection?


I have a DataGrid where the ItemsSource is bound to an ObservableCollection

<DataGrid ItemsSource="{Binding Items}">

Each item in the ObservableCollection also has an ObservableCollection of strings.

One of the columns is a DataGridTemplateColumn that contains a ComboBox. I would like each row's ComboBox to contain items in the ObservableCollection of strings in that row's ViewModel. If I bind it normally, this works. However, I can't seem to get it to work if I am using a CompositeCollection.

<DataGridTemplateColumn Header="Column Title">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox SelectedValue="{Binding Selected, UpdateSourceTrigger=PropertyChanged}">
                <ComboBox.ItemsSource>
                    <CompositeCollection>
                        <CollectionContainer Collection="{Binding ???}" />
                        <ComboBoxItem>
                            <TextBlock>
                                <Hyperlink Command="{Binding DataContext.EditList, Source={x:Reference myGridName}}">Edit List</Hyperlink>
                            </TextBlock>
                        </ComboBoxItem>
                    </CompositeCollection>
                </ComboBox.ItemsSource>
            </ComboBox>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

I'm not sure what to use for the Binding to get it to work. Without the CompositeCollection, I can simply do:

<ComboBox ItemsSource="{Binding SubItems}">

In searching, I know you need to set a source for the CollectionContainer, but most examples were for setting it to a static list that's the same for all rows. I need each row to bind to the ObservableCollection in that row's ViewModel.

I've tried:

<CollectionContainer Collection="{Binding DataContext.SubItems, RelativeSource={RelativeSource AncestorType=ComboBox}}" />

But that results in an error of:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ComboBox', AncestorLevel='1'' ...

Solution

  • You can use the following DataTemplate:

    <DataTemplate>
        <ComboBox x:Name="cb"
                                SelectedValue="{Binding Selected, UpdateSourceTrigger=PropertyChanged}">
            <ComboBox.Resources>
                <DiscreteObjectKeyFrame x:Key="proxy" Value="{Binding ElementName=cb}"/>
            </ComboBox.Resources>
            <ComboBox.ItemsSource>
                <CompositeCollection>
                    <CollectionContainer Collection="{Binding Value.DataContext.SubItems, Source={StaticResource proxy}}" />
                </CompositeCollection>
            </ComboBox.ItemsSource>
        </ComboBox>
    </DataTemplate>
    

    x:Refefrence comes from this explanation. However, this answer is not enough. In fact, you need a proxy as explained in this answer.

    Hope it helps.