WPF DataGridTemplateColumn 与 ComboBox 绑定(MVVM 模式) [英] WPF DataGridTemplateColumn with ComboBox Binding (MVVM pattern)

查看:27
本文介绍了WPF DataGridTemplateColumn 与 ComboBox 绑定(MVVM 模式)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将疯狂使用以下 WPF DataGrid+ComboBox 场景.

I'm going bonkers with the following WPF DataGrid+ComboBox scenario.

我有一组看起来像的类;

I have a set of classes which look like;

class Owner
{
    int ID { get; }
    string Name { get; }

    public override ToString()
    { 
        return this.Name;
    }
}

class House
{
    int ID { get; }
    Owner HouseOwner { get; set; }
}

class ViewModel
{
    ObservableCollection<Owner> Owners;
    ObservableCollection<House> Houses
}

现在我想要的结果是一个 DataGrid,它显示了 House 类型的行列表,在其中一列中是一个 ComboBox,它允许用户更改 House 的值.房主.

Now my desired outcome is a DataGrid which shows a list of rows of type House, and in one of the columns, is a ComboBox which allows the user to change the value of House.HouseOwner.

在这种情况下,网格的 DataContext 是 ViewModel.Houses,而对于 ComboBox,我希望将 ItemsSource 绑定到 ViewModel.Owners.

In this scenario, the DataContext for the grid is ViewModel.Houses and for the ComboBox, I want the ItemsSource to be bound to ViewModel.Owners.

这甚至可能吗?我很担心这个……我能做的最好的事情就是正确地绑定 ItemsSource,但是 ComboBox(在 DataGridTemplateColumn 内)没有在每一行中显示 House.HouseOwner 的正确值.

Is this even possible? I'm going mental with this... the best I've been able to do is to correctly get the ItemsSource bound, however the ComboBox (inside a DataGridTemplateColumn) is not showing the correct values for House.HouseOwner in each row.

注意:如果我从图片中取出 ComboBox 并在 DataTemplate 中放置一个 TextBlock,我可以正确地看到每一行的值,但同时获得一个 ItemsSource 并在选择中显示正确的值不是为我工作...

NOTE: If I take the ComboBox out of the picture and put a TextBlock in the DataTemplate instead, I can correctly see the values for each row, but getting both an ItemsSource as well as show the correct value in the selection is not working for me...

在我背后的代码中,我将窗口上的 DataContext 设置为 ViewModel,而在网格上,DataContext 设置为 ViewModel.Houses.对于除此组合框之外的所有内容,它都可以正常工作...

Inside my code behind, I have set the DataContext on the Window to ViewModel and on the grid, the DataContext is set to ViewModel.Houses. For everything except this combobox, it's working...

我的违规列的 XAML 看起来像;

My XAML for the offending column looks like;

<DataGridTemplateColumn Header="HouseOwner">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox ItemsSource="{Binding Path=DataContext.Owners, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                        DisplayMemberPath="Name"
                        SelectedItem="{Binding HouseOwner, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
                        SelectedValue="{Binding HouseOwner.ID, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Mode=OneWay}"
                        SelectedValuePath="ID" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

希望得到一些帮助...不过似乎需要一点巫毒...

Would love some help on this one... seems like a bit of Voodoo is required though...

推荐答案

正如 default.kramer 所说,您需要从 RelativeSource 的绑定中删除 >SelectedItemSelectedValue 像这样(请注意,您应该将 Mode=TwoWay 添加到您的绑定中,以便组合框中的更改反映在您的模型中).

as default.kramer said, you need to remove the RelativeSource from your bindings for the SelectedItem and SelectedValue like this (notice that you should add Mode=TwoWay to your binding so that the change in the combobox is reflected in your model).

<DataGridTemplateColumn Header="House Owner">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox
                ItemsSource="{Binding Path=DataContext.Owners, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                DisplayMemberPath="Name"
                SelectedItem="{Binding HouseOwner, Mode=TwoWay}"
                SelectedValue="{Binding HouseOwner.ID}"
                SelectedValuePath="ID"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

然而,与他所说的不同,您不必删除 SelectedValue 的绑定.事实上,如果你删除它,它就不会工作(SelectedValueSelectedValuePath 都应该在这里设置,就像你所做的那样),因为这就是允许绑定的原因识别从组合框到 DataGrid 的 HouseOwner 属性的选择的机制.

However, unlike he said, you don't have to remove the binding for the SelectedValue. In fact, if you remove it, it won't work (both SelectedValue and SelectedValuePath should be set here, as you've done), because that's what's allowing the binding mechanism to identify the selection from the combobox to the DataGrid's HouseOwner property.

SelectedValue/SelectedValuePath 组合非常有趣.SelectedValuePath 告诉数据绑定当前选中的 Owner 对象的 ID 属性代表它的 valueSelectedValue 告诉它该值应该绑定到 HouseOwner.ID,它是 DataGrid 上的选定对象.

SelectedValue/SelectedValuePath combination is very interesting. SelectedValuePath tells the databinding that the ID property of the Owner object currently selected represents its value, SelectedValue tells it that that value should be bound to the HouseOwner.ID which is the selected object on the DataGrid.

因此,如果删除这些绑定,数据绑定机制将唯一知道的是选择了什么对象",并在 ComboBox 中的所选项目与 HouseOwner 属性之间建立对应关系在 DataGrid 中的选定项上,它们必须是相同的对象引用".这意味着,例如,以下内容不起作用:

Therefore, if you remove those binding, the only thing the databinding mechanism will know is "what object is selected", and to make the correspondence between the selected item in the ComboBox and the HouseOwner property on the selected item in the DataGrid, they have to be "the same object reference". Meaning that, for example, the following wouldn't work:

Owners = new ObservableCollection<Owner>
                {
                    new Owner {ID = 1, Name = "Abdou"},
                    new Owner {ID = 2, Name = "Moumen"}
                };
Houses = new ObservableCollection<House>
                {
                    new House {ID = 1, HouseOwner = new Owner {ID = 1, Name = "Abdou" }},
                    new House {ID = 2, HouseOwner = new Owner {ID = 2, Name = "Moumen"}}
                };

(请注意,Houses 集合中的HouseOwners"与 Owners 集合中的不同(新)).但是,以下工作:

(notice that the "HouseOwners" of the Houses collection are different (new) from the ones in the Owners collection). However, the following would work:

Owners = new ObservableCollection<Owner>
                {
                    new Owner {ID = 1, Name = "Abdou"},
                    new Owner {ID = 2, Name = "Moumen"}
                };
Houses = new ObservableCollection<House>
                {
                    new House {ID = 1, HouseOwner = Owners[0]},
                    new House {ID = 2, HouseOwner = Owners[1]}
                };

希望这有帮助:)

更新:在第二种情况下,您可以通过覆盖 Owner 上的 Equals 来获得相同的结果,而不会使引用相同类(自然,因为它首先用于比较对象).(感谢@RJ Lohan 在下面的评论中注意到这一点)

Update: in the second case, you can get the same result without having the references being the same by overriding Equals on the Owner class (naturally, since it's used to compare the objects in the first place). (thanks to @RJ Lohan for noting this in the comments below)

这篇关于WPF DataGridTemplateColumn 与 ComboBox 绑定(MVVM 模式)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆