.net – Binding ItemsSource of a ComboBoxColumn in WPF DataGrid

bindingdatagridcomboboxcolumnnetwpfwpfdatagrid

I have two simple Model classes and a ViewModel…

public class GridItem
{
    public string Name { get; set; }
    public int CompanyID { get; set; }
}

public class CompanyItem
{
    public int ID { get; set; }
    public string Name { get; set; }
}

public class ViewModel
{
    public ViewModel()
    {
        GridItems = new ObservableCollection<GridItem>() {
            new GridItem() { Name = "Jim", CompanyID = 1 } };

        CompanyItems = new ObservableCollection<CompanyItem>() {
            new CompanyItem() { ID = 1, Name = "Company 1" },
            new CompanyItem() { ID = 2, Name = "Company 2" } };
    }

    public ObservableCollection<GridItem> GridItems { get; set; }
    public ObservableCollection<CompanyItem> CompanyItems { get; set; }
}

…and a simple Window:

<Window x:Class="DataGridComboBoxColumnApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding GridItems}" >
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Name}" />
                <DataGridComboBoxColumn ItemsSource="{Binding CompanyItems}"
                                    DisplayMemberPath="Name"
                                    SelectedValuePath="ID"
                                    SelectedValueBinding="{Binding CompanyID}" />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

The ViewModel is set to the MainWindow's DataContext in App.xaml.cs:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        MainWindow window = new MainWindow();
        ViewModel viewModel = new ViewModel();

        window.DataContext = viewModel;
        window.Show();
    }
}

As you can see I set the ItemsSource of the DataGrid to the GridItems collection of the ViewModel. This part works, the single Grid line with Name "Jim" is displayed.

I also want to set the ItemsSource of the ComboBox in every row to the CompanyItems collection of the ViewModel. This part does not work: The ComboBox remains empty and in the Debugger Output Window I see an error message:

System.Windows.Data Error: 2 : Cannot
find governing FrameworkElement or
FrameworkContentElement for target
element.
BindingExpression:Path=CompanyItems;
DataItem=null; target element is
'DataGridComboBoxColumn'
(HashCode=28633162); target property
is 'ItemsSource' (type 'IEnumerable')

I believe that WPF expects CompanyItems to be a property of GridItem which is not the case, and that's the reason why the binding fails.

I've already tried to work with a RelativeSource and AncestorType like so:

<DataGridComboBoxColumn ItemsSource="{Binding CompanyItems, 
    RelativeSource={RelativeSource Mode=FindAncestor,
                                   AncestorType={x:Type Window}}}"
                        DisplayMemberPath="Name"
                        SelectedValuePath="ID"
                        SelectedValueBinding="{Binding CompanyID}" />

But that gives me another error in the debugger output:

System.Windows.Data Error: 4 : Cannot
find source for binding with reference
'RelativeSource FindAncestor,
AncestorType='System.Windows.Window',
AncestorLevel='1''.
BindingExpression:Path=CompanyItems;
DataItem=null; target element is
'DataGridComboBoxColumn'
(HashCode=1150788); target property is
'ItemsSource' (type 'IEnumerable')

Question: How can I bind the ItemsSource of the DataGridComboBoxColumn to the CompanyItems collection of the ViewModel? Is it possible at all?

Thank you for help in advance!

Best Answer

Pls, check if DataGridComboBoxColumn xaml below would work for you:

<DataGridComboBoxColumn 
    SelectedValueBinding="{Binding CompanyID}" 
    DisplayMemberPath="Name" 
    SelectedValuePath="ID">

    <DataGridComboBoxColumn.ElementStyle>
        <Style TargetType="{x:Type ComboBox}">
            <Setter Property="ItemsSource" Value="{Binding Path=DataContext.CompanyItems, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
        </Style>
    </DataGridComboBoxColumn.ElementStyle>
    <DataGridComboBoxColumn.EditingElementStyle>
        <Style TargetType="{x:Type ComboBox}">
            <Setter Property="ItemsSource" Value="{Binding Path=DataContext.CompanyItems, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
        </Style>
    </DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>

Here you can find another solution for the problem you're facing: Using combo boxes with the WPF DataGrid

Related Topic