5

I would like to bind third column to a CollectionBindingTwo property that is within Window's DataContext and not inside DataContext of an Items from CollectionBindingOne.

By defining the second collection inside <DataGrid> WPF assumes local scope or something, and points to a property within Items of ItemsSource (CollectionBindingOne).

<DataGrid DockPanel.Dock="Top" ItemsSource="{Binding CollectionBindingOne}" AutoGenerateColumns="False">
    <DataGridTextColumn Header="One" Binding="{Binding PropOne}"/>
    <DataGridTextColumn  Header="Two" Binding="{Binding PropTwo}"/>
    <DataGridComboBoxColumn Header="Three" ItemsSource="{Binding CollectionBindingTwo}"/>
</DataGrid>

For example, this works because ComboBox is not inside a <DataGrid>:

<ComboBox IsEditable="True" ItemsSource="{Binding CollectionBindingTwo}"></ComboBox>
daniele3004
  • 13,072
  • 12
  • 67
  • 75
Sergey
  • 939
  • 1
  • 6
  • 13

2 Answers2

3

The DataGridComboBoxColumn is not a part of the Visual Tree so the usual RelativeSource/ElementName binding formats won't work. You can use a workaround by defining the ElementStyle and EditingStyle where those binding formats will work. Another option is to use a BindingProxy which I use for other spots and will save some XAML when there is no other reason to define an ElementStyle/EditingStyle.

This is the BindingProxy class which inherits from Freezable.

public class BindingProxy : Freezable
{
    #region Overrides of Freezable

    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }

    #endregion

    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Data.
    // This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data",
                                    typeof(object),
                                    typeof(BindingProxy),
                                    new UIPropertyMetadata(null));
}

Now your xaml looks like this:

<DataGrid DockPanel.Dock="Top"
          ItemsSource="{Binding CollectionBindingOne}"
          AutoGenerateColumns="False">
    <DataGrid.Resources>
        <helper:BindingProxy x:Key="proxy"
                             Data="{Binding }" />
    </DataGrid.Resources>
    <DataGrid.Columns>
        <DataGridTextColumn Header="One"
                            Binding="{Binding PropOne}" />
        <DataGridTextColumn Header="Two"
                            Binding="{Binding PropTwo}" />
        <DataGridComboBoxColumn Header="Three" 
                                ItemsSource="{Binding Data.CollectionBindingTwo,
                                              Source={StaticResource proxy}}" />
</DataGrid>

Don't forget to declare the helper namespace import at the top of your Window/UserControl.

Community
  • 1
  • 1
Lee O.
  • 3,212
  • 2
  • 26
  • 36
  • This worked, thank you for the answer. I went for the Styles option, since I don't expect having to do this anywhere else at this time. If I do, using your BindingProxy class would make more sense (thanks for that too). – Sergey Jul 30 '14 at 17:14
2

That's what the [RelativeSource][1] bindings are for. In this case you should be able to target parent data context by way of the the DataGrid's data context:

<DataGrid>
    <DataGridComboBoxColumn Header="Three" ItemsSource="{Binding  
        RelativeSource={RelativeSource AncestorType=DataGrid},
        Path=DataContext.CollectionBindingTwo}" />
</DataGrid>

An ElementName binding should also work:

<DataGrid x:Name="dataGrid">
    <DataGridComboBoxColumn Header="Three" 
        ItemsSource="{Binding ElementName=dataGrid, Path=DataContext.CollectionBindingTwo}" />
</DataGrid>
McGarnagle
  • 101,349
  • 31
  • 229
  • 260
  • 1
    Thank you for the answer. However this did not work, most likely because of the VisualTree membership as per Lee's answer. +1 because this would work in other situations and I did not know you can access DataContext from the Binding Path. – Sergey Jul 30 '14 at 17:11
  • 1
    @Sergey thanks -- check out this answer also, for an alternate approach using `x:Reference`: http://stackoverflow.com/a/25021052/1001985 – McGarnagle Jul 30 '14 at 17:36