带有ComboBox绑定的WPF DataGridTemplateColumn(MVVM模式)

RJ *_*han 11 wpf binding datagrid combobox datagridtemplatecolumn

我正在使用以下WPF DataGrid + ComboBox方案来疯狂.

我有一组看起来像的课程;

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
}
Run Code Online (Sandbox Code Playgroud)

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

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

这甚至可能吗?我正在努力解决这个问题...我能做的最好的事情就是正确地绑定ItemsSource,但是ComboBox(在DataGridTemplateColumn中)没有在每一行中显示House.HouseOwner的正确值.

注意:如果我将ComboBox从图片中取出并将TextBlock放入DataTemplate中,我可以正确地看到每行的值,但同时获取ItemsSource以及在选择中显示正确的值对我来说不起作用...

里面的背后我的代码,我已经设置窗口在DataContext到视图模型和对电网的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>
Run Code Online (Sandbox Code Playgroud)

我会喜欢这方面的一些帮助......看起来有点像Voodoo虽然......

Abd*_*men 14

作为default.kramer说,你需要删除RelativeSource从您绑定的SelectedItemSelectedValue像这样的(请注意,你应该添加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>
Run Code Online (Sandbox Code Playgroud)

但是,与他说的不同,你不必删除绑定SelectedValue.事实上,如果你删除它,它不会工作(包括SelectedValueSelectedValuePath应设置在这里,因为你做了),因为那是什么让绑定机制,以从组合框到DataGrid的识别选择HouseOwner属性.

SelectedValue/ SelectedValuePath组合非常有趣.SelectedValuePath告诉数据绑定当前所选对象的ID属性Owner表示其,SelectedValue告诉它该值应该绑定到HouseOwner.IDDataGrid上的选定对象.

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

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"}}
                };
Run Code Online (Sandbox Code Playgroud)

(请注意,Houses系列的"HouseOwners"与Owners系列中的"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]}
                };
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助 :)

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


RJ *_*han 8

感谢所有人的帮助 - 我终于找出了为什么我无法选择ComboBox项目 - 是由于我在使用DataGridComboBoxColumn时附加到单元格样式的鼠标预览事件处理程序.

感谢其他人的帮助,为自己打了一针.

另外,作为一个笔记; 这对我有用的唯一方法是额外的;

IsSynchronizedWithCurrentItem="False"
Run Code Online (Sandbox Code Playgroud)

添加到ComboBox,否则由于某种原因它们都显示相同的值.

另外,我似乎不需要在我的Binding中使用SelectedValue/SelectedValuePath属性,我相信因为我在绑定的Owner类型中覆盖了Equals.

最后,我必须明确地设定;

Mode = TwoWay,UpdateSourceTrigger = PropertyChanged

在Binding中,以便在ComboBox发生更改时将值写回绑定项.

所以,绑定的最终(工作)XAML看起来像这样;

    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox 
                ItemsSource="{Binding Path=DataContext.Owners,  
                RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                IsSynchronizedWithCurrentItem="False"
                SelectedItem="{Binding HouseOwner, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"  />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
Run Code Online (Sandbox Code Playgroud)

干杯!

RJ