Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
503 views
in Technique[技术] by (71.8m points)

wpf - Bind ViewModel property to DataGridComboBoxColum

I am trying to use an enum in a Datagrid. Let me show you two ways that it can work. First, I create a ComboBox inside the DataGrid, the DataContext.MyOptions returns a list of Strings for all values of enum.

<DataGridTemplateColumn Header="Enum1">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox ItemsSource="{Binding DataContext.MyOptions, RelativeSource={RelativeSource AncestorType=Window}}" 
                      SelectedItem="{Binding Enum1, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource MyConverter}}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

Next I am trying to use the DataGridComboBoxColumn, but to get this working I have to add the ElementStyle and EditingElementStyle (I copied it from somewhere)

<DataGridComboBoxColumn Header="Enum1" Width="*" 
                        SelectedItemBinding="{Binding Enum1, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource MyConverter}}">
    <DataGridComboBoxColumn.ElementStyle>
        <Style TargetType="ComboBox">
            <Setter Property="ItemsSource" Value="{Binding Path=DataContext.MyOptions, RelativeSource={RelativeSource AncestorType=Window}}" />
        </Style>
    </DataGridComboBoxColumn.ElementStyle>
    <DataGridComboBoxColumn.EditingElementStyle>
        <Style TargetType="ComboBox">
            <Setter Property="ItemsSource" Value="{Binding Path=DataContext.MyOptions, RelativeSource={RelativeSource AncestorType=Window}}" />
        </Style>
    </DataGridComboBoxColumn.EditingElementStyle>

</DataGridComboBoxColumn>

Now my question is, why does the below not work. The column show empty but the value is there.

<DataGridComboBoxColumn Header="Enum1" Width="*" 
                        ItemsSource="{Binding Path=DataContext.MyOptions, RelativeSource={RelativeSource AncestorType=Window}}" 
                        SelectedItemBinding="{Binding Enum1, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource MyConverter}}">
</DataGridComboBoxColumn>

In the output window I see the following error:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Window', AncestorLevel='1''. BindingExpression:Path=DataContext.MyOptions; DataItem=null; target element is 'DataGridComboBoxColumn' (HashCode=59316889); target property is 'ItemsSource' (type 'IEnumerable')
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

DataGrid Columns dont come under the visualtree of their parent. Thats why they cannot inherit the DataContext from parent nor they can refer to Ancestor.

DataGrid rows and cells on the other hand comes under the visualtree and hence can find ancestor and inherit DataContext.

In order to bind the Column, you will need to use the BindingProxy.

To do it what you can do is define one resource in your Window Resource as

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));
}

<DataGrid.Resources>
    <local:BindingProxy x:Key="ProxyElement" Data="{Binding}" />
</DataGrid.Resources>

and then use this element to bind in column like

<DataGridComboBoxColumn Header="Enum1" Width="*" 
                        ItemsSource="{Binding Path=Data.MyOptions, Source={StaticResource ProxyElement}" 
                        SelectedItemBinding="{Binding Enum1, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource MyConverter}}">
</DataGridComboBoxColumn>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...