这个DataGridComboBoxColumn绑定语法有什么问题?

时间:2013-07-31 18:21:30

标签: wpf data-binding selectedvalue datagridcomboboxcolumn

我找到了很多这个问题的答案,但我似乎无法正确理解语法。考虑到解释here和我发现的许多其他人,我已经尝试了我能想到的每一个逻辑组合,但三周之后它仍然没有找到我。我只需要正确获取XAML的语法。

类:(为简单/保密而重命名)

UserControl1 - 包含三个全局列表,称为Streets,Houses和Cars

Street - 包含两个仅列出相关房屋和汽车的列表,名为MyHouses和MyCars

House - 在DataGrid中显示,其中一列是DataGridComboboxColumn,用于选择与此House关联的Street。在其中声明了一个名为Street的街道属性,以跟踪此情况并在get / set中执行其他计算。

Car - 在DataGrid中显示,其中一列是DataGridComboboxColumn,用于选择与此Car关联的Street。在其中声明了一个名为Street的街道属性,以跟踪此情况并在get / set中执行其他计算。

如果需要,我可以重构后面的代码以匹配上面的内容并发布。

XAML

<DataGrid ItemsSource="{Binding Streets, Mode=TwoWay}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Street"  Binding="{Binding StreetID, Mode=TwoWay}"/>
    </DataGrid.Columns>
</DataGrid>
<DataGrid ItemsSource="{Binding Cars, Mode=TwoWay}">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding CarID, Mode=TwoWay}"/>
        <DataGridComboBoxColumn 
        ItemsSource="{Binding Streets, RelativeSource={RelativeSource FindAncestor,AncestorType=UserControl1}, Mode=OneWay}"
        SelectedItemBinding="{Binding Street}"
        SelectedValue="{Binding StreetID}"
        SelectedValuePath="StreetID" 
        DisplayMemberPath="StreetID">
            <DataGridComboBoxColumn.ElementStyle>
                <Style TargetType="ComboBox">
                    <Setter Property="ItemsSource" Value="{Binding Streets, RelativeSource={RelativeSource FindAncestor,AncestorType=UserControl1}, Mode=OneWay}"/>
                    <Setter Property="IsReadOnly" Value="True"/>
                </Style>
            </DataGridComboBoxColumn.ElementStyle>
            <DataGridComboBoxColumn.EditingElementStyle>
                <Style TargetType="ComboBox">
                    <Setter Property="ItemsSource" Value="{Binding Streets, RelativeSource={RelativeSource FindAncestor,AncestorType=UserControl1}, Mode=OneWay}"/>
                </Style>
            </DataGridComboBoxColumn.EditingElementStyle>
        </DataGridComboBoxColumn>
    </DataGrid.Columns>
</DataGrid>
<DataGrid ItemsSource="{Binding Houses, Mode=TwoWay}">
    <!--copy of Cars with changed names-->
</DataGrid>

2 个答案:

答案 0 :(得分:1)

如果我理解你正在尝试做的事情,我认为这就是你所追求的(基于你的描述中的模型):

请注意,由于我的模型,我的一些变量名称略有不同,例如UserControl

<DataGridComboBoxColumn 
    SelectedItemBinding="{Binding Street}"
    DisplayMemberPath="StreetName">
    <DataGridComboBoxColumn.ElementStyle>
        <Style TargetType="ComboBox">
            <Setter Property="ItemsSource" Value="{Binding Streets, RelativeSource={RelativeSource FindAncestor,AncestorType=UserControl}, Mode=OneWay}"/>
            <Setter Property="IsReadOnly" Value="True"/>
         </Style>
    </DataGridComboBoxColumn.ElementStyle>
    <DataGridComboBoxColumn.EditingElementStyle>
        <Style TargetType="ComboBox">
            <Setter Property="ItemsSource" Value="{Binding Streets, RelativeSource={RelativeSource FindAncestor,AncestorType=UserControl}, Mode=OneWay}"/>
        </Style>
     </DataGridComboBoxColumn.EditingElementStyle>
 </DataGridComboBoxColumn>

对我来说,这会在数据网格中显示我的Cars,其中包含所有相关列和可选择的街道(您可以以类似方式调整Houses)。

正如我认为您已经阅读过,DataGridComboBoxColumn对于解析其DataContext有点奇怪。当您尝试将ItemsSource设置在DataGridComboBoxColumn的顶部时,会造成混淆。

这应该适用于您所描述的示例(我使用Cars建模并且Houses使用Street对象作为跟踪属性,而不是ID)。

如果您决定要合并SelectedValue并使用返回的Street ID(在CarHouse上存储为ID属性,我认为您将拥有用你的风格模板中的另一个setter来做。

修改 我使用的样机(在XAML中将Datacontext设置为self)。 N.B对象不会相互跟踪(因为我不确定你的设置是什么)。

public partial class UserControl1 : UserControl
{
    public List<Street> Streets { get; set; }
    public List<House> Houses { get; set; }
    public List<Car> Cars { get; set; }

    public UserControl1()
    {
        Streets = new List<Street>();
        Houses = new List<House>();
        Cars = new List<Car>();

        Street streetOne = new Street() { StreetID = 1, Name = "Street One" };
        Street streetTwo = new Street() { StreetID = 1, Name = "Street Two" };
        Car carOne = new Car() { CarID = 1, Name = "KITT", MyStreet = streetOne };
        Car carTwo = new Car() { CarID = 2, Name = "Car 2", MyStreet = streetTwo };
        House houseOne = new House() { HouseID = 1, Name = "House 1", MyStreet = streetOne };

        InitializeComponent();

        streetOne.MyCars.Add(carOne);
        streetOne.MyHouses.Add(houseOne);
        streetTwo.MyCars.Add(carTwo);
        Cars.Add(carOne);
        Cars.Add(carTwo);
        Houses.Add(houseOne);
        Streets.Add(streetOne);
        Streets.Add(streetTwo); 
    }
}

public class Car
{
    public int CarID { get; set; }
    public string Name { get; set; }
    private Street _street;
    public Street MyStreet
    {
        get { return this._street; }
        set { this._street = value; }
    }
}

public class House
{
    public int HouseID { get; set; }
    public string Name { get; set; }
    public Street MyStreet { get; set; }
}

public class Street
{
    public int StreetID { get; set; }
    public string Name { get; set; }
    public List<House> MyHouses { get; set; }
    public List<Car> MyCars { get; set; }

    public Street()
    {
        MyHouses = new List<House>();
        MyCars = new List<Car>();
    }
}

答案 1 :(得分:0)

尽管全局列表是ObservableCollections,但它们似乎不会在后面的代码构造函数中触发PropertyChangedEvents。我在添加内容之后在代码中设置了ItemsSource,它现在似乎工作正常。真正没有意义的是,一旦Streets出现在House和Car对象中,属性更改事件就会被触发,因为两者都知道彼此的变化。使用Chris在后面的代码中发布的设置工作,所以我将他的帖子标记为答案。我不知道为什么当只与XAML中的设置绑定时列表为空。