本文介绍了将ViewModel绑定到DataGridComboBoxColum的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在Datagrid中使用枚举。让我告诉你两种可以工作的方法。
首先,我在DataGrid中创建一个ComboBox,DataContext.MyOptions返回所有枚举值的字符串列表。

 < 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>

接下来我试图使用DataGridComboBoxColumn,但为了得到这个工作,我必须添加ElementStyle和EditingElementStyle(我从某处复制)

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

< / DataGridComboBoxColumn>

现在我的问题是,为什么以下不起作用。该列显示为空,但值为。

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

在输出窗口中,我看到以下错误:

  System.Windows.Data错误:4:找不到与引用'RelativeSource FindAncestor,AncestorType ='System.Windows.Window',AncestorLevel ='1'绑定的源代码。 BindingExpression:Path = DataContext.MyOptions; DataItem = null;目标元素是'DataGridComboBoxColumn'(HashCode = 59316889);目标属性是'ItemsSource'(类型'IEnumerable')


解决方案

DataGrid列不会在其父级的视觉效果之下。这就是为什么他们不能从父级继承DataContext ,也不能引用Ancestor。



DataGrid上的行和单元格另一方面是在visualtree下面,因此可以找到祖先并继承DataContext。



为了绑定列,你需要使用BindingProxy 。



要做到这一点,您可以做的是在Windows资源中定义一个资源

 code> public class BindingProxy:Freezable 
{
#region覆盖Freezable

保护覆盖Freezable CreateInstanceCore()
{
返回新的BindingProxy ();
}

#endregion

公共对象数据
{
get {return(object)GetValue(DataProperty); }
set {SetValue(DataProperty,value); }
}

//使用DependencyProperty作为Data的后备存储。这使得动画,样式,绑定等...
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register(Data,typeof(object),typeof(BindingProxy),new UIPropertyMetadata(null)) ;
}

< DataGrid.Resources>
< local:BindingProxy x:Key =ProxyElementData ={Binding}/>
< /DataGrid.Resources>

然后使用此元素在列中绑定,如

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


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')
解决方案

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>

这篇关于将ViewModel绑定到DataGridComboBoxColum的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-26 22:18
查看更多