21

I have a simple object like:

class Item
{
  ....

  public String Measure { get; set; }
  public String[] Measures {get; }
}

Which I am trying to bind to a DataGrid with two text columns and a combo box column. For the combo box column, property Measure is the current selection and Measures the possible values.

My XAML is:

<DataGrid Name="recipeGrid" AutoGenerateColumns="False" 
          CellEditEnding="recipeGrid_CellEditEnding" CanUserAddRows="False"
          CanUserDeleteRows="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Food" Width="Auto"
                            Binding="{Binding Food.Name}" />
        <DataGridTextColumn Header="Quantity" IsReadOnly="False"
                            Binding="{Binding Quantity}" />

        <DataGridComboBoxColumn Header="Measure" Width="Auto"
                                SelectedItemBinding="{Binding Path=Measure}"
                                ItemsSource="{Binding Path=Measures}" />

    </DataGrid.Columns>
</DataGrid>

The text column are displayed just fine but the combobox is not - the values are not displayed at all. The binding error is:

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

How do I fix this?

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
georgiosd
  • 3,038
  • 3
  • 39
  • 51

4 Answers4

20

This is hands down the best solution:

http://wpfthoughts.blogspot.com/2015/04/cannot-find-governing-frameworkelement.html

The idea here is that you declare a CollectionViewSource as a static resource and then declaratively bind it to ItemsSource of the DataGridComboBoxColumn.

Create and bind a static CollectionViewSource:

 <Page.Resources>
     <CollectionViewSource x:Key="Owners" Source="{Binding Owners}"/>
 </Page.Resources>

And then bind your target ItemsSource:

ItemsSource="{Binding Source={StaticResource Owners}}"
nh43de
  • 813
  • 11
  • 11
  • 4
    Simple and effective! You can also put the `CollectionViewSource` directly in `` if it's not used elsewhere. – piedar Jun 30 '16 at 19:02
  • I know this is an old post, but how does this work when the ObservableCollection lives in the ViewModel and not the View? – Holden Jun 22 '20 at 23:58
3

The problem lies in that Columns does no inherit DataContext.

See more here Binding in a WPF data grid text column

here blogs.msdn.com/vinsibal/archive/2008/12/17/wpf-datagrid-dynamically-updating-datagridcomboboxcolumn.aspx

and here http://blogs.msdn.com/jaimer/archive/2008/11/22/forwarding-the-datagrid-s-datacontext-to-its-columns.aspx

Community
  • 1
  • 1
ThomasAndersson
  • 1,844
  • 12
  • 23
  • 1
    Well, if that is true then why do the text columns work but the combo box column doesn't?? – georgiosd May 25 '10 at 11:56
  • If I understand it correctly it is because the text columns are bound directly to a property in the DataGrid's ItemsSource, DataGrid.ItemsSource->Item->Measure and the ComboBox are implicitly bound to DataContext of the Item, which is not inherited. DataGrid.ItemsSource->Item->DataContext->Measures/Measure This is how I understood it, admittedly I see now that I am not very good at explaining it. Possibly someone can do it better than me. – ThomasAndersson May 25 '10 at 12:39
  • 1
    > Note that the reason Binding does work is because the internal code dynamically sets the binding of DataGridColumn.Binding to the DataGridCell.Content (http://blogs.msdn.com/b/vinsibal/archive/2009/04/07/5-random-gotchas-with-the-wpf-datagrid.aspx) – Maxence Apr 28 '15 at 11:57
2

If your measures are common for all objects, then you can make measures static

public String[] Measures { get; }

And your xaml will use it as it's shown below:

<DataGridComboBoxColumn
    Header="Role"
    SelectedValueBinding="{Binding Role}"
    ItemsSource="{Binding Source={x:Static local:ProjectsDataContext.Roles}}"
    DisplayMemberPath="Name"/>

Hopefully, it will help.

George Lanetz
  • 300
  • 5
  • 18
0

If you would like to bind to the data context item for the row to a combobox, you can use a DataGridTemplateColumn with a ComboBox in its template. Note that you have to add the Mode=TwoWay, UpdateSourceTrigger=PropertyChanged properties to the SelectedItem binding or it will not update properly.

<DataGridTemplateColumn Header="My Stuff">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox ItemsSource="{Binding MyThings}"
                SelectedItem="{Binding SelectedThing, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
jcox
  • 786
  • 8
  • 11