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

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

问题描述

我正在使用以下WPF DataGrid + ComboBox方案。



我有一组类似于

 类所有者
{
int ID {get; }
string Name {get; }

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

class House
{
int ID {get; }
所有者HouseOwner {get;组; }
}

class ViewModel
{
ObservableCollection< Owner>拥有者;
ObservableCollection< House>房子
}

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



在这种情况下,网格的DataContext是 ViewModel.Houses ,对于ComboBox,我希望ItemsSource绑定到ViewModel。所有者。



这是否可以?我正在精神上这样做...我能够做的最好的事情是正确地获取ItemsSource绑定,但是ComboBox(DataGridTemplateColumn里面)没有显示每行中House.HouseOwner的正确值。 / p>

注意:如果我把ComboBox从图片中取出并将TextBlock放在DataTemplate中,我可以正确看到每一行的值,但是将ItemsSource以及显示选择中的正确值不适用于我...



在我的代码背后,我已经将窗口上的DataContext设置为 ViewModel ,在网格上,DataContext设置为 ViewModel.Houses 。对于除了这个组合框之外的所有内容,它正在工作...



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

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

想要一些帮助这个...似乎有一点Voodoo是必需的...

解决方案

as default.kramer 说,你需要删除 RelicateSource 从您的绑定为 SelectedItem SelectedValue 这样(注意你应该添加 Mode = TwoWay 到您的绑定,以便组合框中的更改反映在您的模型中)。

 < 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 。事实上,如果你删除它,它将不起作用( SelectedValue SelectedValuePath 应该设置在这里,因为您已经完成了),因为这是允许绑定机制识别从组合框到DataGrid的 HouseOwner 属性的选择。



SelectedValue / SelectedValuePath 组合非常有趣。 SelectedValuePath 告诉数据绑定,所有者 ID 当前选中的对象表示其 SelectedValue 告诉它该值应绑定到 HouseOwner.ID 它是DataGrid上选择的对象。



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

 所有者= 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}}
};

(请注意,房屋集合的HouseOwners与业主收藏)。但是,以下工作:

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

希望这有帮助:)



strong>更新:在第二种情况下,您可以获得相同的结果,而不必在所有者等于的引用相同c> class(自然,因为它用于比较首先的对象)。 (感谢@ RJ Lohan ,在下面的评论中注明)


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
}

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.

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.

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.

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

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

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

解决方案

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>

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

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

(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]}
                };

Hope this helps :)

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天全站免登陆