C# 如何实现包含父项和子项的组合框层次结构?

C# 如何实现包含父项和子项的组合框层次结构?,c#,wpf,combobox,C#,Wpf,Combobox,这篇文章的标题可能需要一些工作,但我很难在不深入细节的情况下表达自己 这就来了 我有一个简单的WPF应用程序,它从第三方API检索州、城市、综合区和建筑的列表 公共类状态 { 公共int Id{get;set;} 公共字符串名称{get;set;} } 公营城市 { 公共int Id{get;set;} public int ParentId{get;set;}//FK to Id处于状态 公共字符串名称{get;set;} } 公共类综合体 { 公共int Id{get;set;} publi

这篇文章的标题可能需要一些工作,但我很难在不深入细节的情况下表达自己

这就来了

我有一个简单的WPF应用程序,它从第三方API检索
城市
综合区
建筑
的列表

公共类状态
{
公共int Id{get;set;}
公共字符串名称{get;set;}
}
公营城市
{
公共int Id{get;set;}
public int ParentId{get;set;}//FK to Id处于状态
公共字符串名称{get;set;}
}
公共类综合体
{
公共int Id{get;set;}
public int ParentId{get;set;}//FK到城市中的Id
公共字符串名称{get;set;}
}
公共班级大楼
{
公共int Id{get;set;}
public int ParentId{get;set;}//FK到复数中的Id
公共字符串名称{get;set;}
}
当填充一些数据时,这些列表可能看起来像这样

StateOptions=新的ObservableCollection
{
新州(){Id=1,Name=“California”},
纽约州(){Id=2,Name=“纽约”},
};
CityOptions=新的可观测集合
{
新城(){Id=1,ParentId=1,Name=“洛杉矶”},
纽约市(){Id=2,ParentId=2,Name=“纽约市”}
};
ComplexOptions=新的可观察收集
{
新复合体(){Id=1,ParentId=1,Name=“洛杉矶国际机场”},
新复合体(){Id=2,ParentId=2,Name=“约翰·F·肯尼迪国际机场”}
};
BuildingOptions=新的ObservableCollection
{
新建建筑(){Id=1,ParentId=1,Name=“Terminal 1”},
新建建筑(){Id=2,ParentId=1,Name=“Terminal 2”},
新建建筑(){Id=3,ParentId=1,Name=“Terminal 3”},
新建建筑(){Id=4,ParentId=2,Name=“Terminal 1”},
新建建筑(){Id=5,ParentId=2,Name=“Terminal 2”},
新建建筑(){Id=6,ParentId=2,Name=“Terminal 3”},
};
使用这些列表,我需要创建一个新对象,
Foo
,然后将其发布回API

公共类Foo
{
公共int Id{get;set;}
公共int StateId{get;set;
公共int-CityId{get;set;
公共int复杂{get;set;
public int BuildingId{get;set;
}
这本身非常简单,因为您可以将列表放在四个可观察的集合中,并使用它们作为四个
ComboBox
元素的
ItemSource
绑定。然后您可以为每个组合框使用
SelectedItem
绑定属性来创建
Foo
对象

如果这些是简单的列表,那么这就很好了,但是请注意
城市
中的
ParentId
字段、
复杂
建筑
模型

因此,这四个列表必须被视为一个层次结构。事实上,名称
ParentId
非常容易引起误解,因为它们没有引用相同类型的另一个实体。当查看
Foo
类时,这一点就很明显了,该类具有上述所有内容的外键

因此,我需要过滤城市组合框中的项目,以仅显示Id等于状态组合框中选定项的父Id的项目。对于复杂组合框和建筑组合框也是如此

为了进一步说明这一点,我更愿意通过创建WPF用户控件来解决这个问题,因为这四个列表将在未来的许多视图中再次出现,并且需要相同的功能。但是,我对所有解决方案都持开放态度。我也更愿意这样做,而不需要额外访问API,因为列表非常大

为方便起见,我在创建了一个演示项目。该项目通过将四个列表视为平面来说明问题,因此,您可以选择洛杉矶国际机场作为综合体,即使纽约被选为该州。这显然是错误的,正是我希望防止用户发现的错误奥林


如果您还有其他问题,请留下评论。

经过一番讨论和尝试,我们找到了一些解决此问题的方法

在大多数情况下,第一种解决方案就足够了,而且可能是most推荐的,因为它很容易在视图模型中用最少的逻辑实现,从而强制使用XAML实现层次结构

然而,我又添加了两个解决方案,因为很多人可能也考虑过这些。事实上,我们最终采用了第三个解决方案,因为第一个解决方案不考虑孤儿,除非您将每个孤儿添加为每个项目的子项

解决方案1(推荐)

正如Sheridan所建议的,您可以构建一个层次数据模型,将
节点
变成
层次节点
。这可能是最简单的解决方案,如果可以的话,我可能会建议您使用此解决方案

公共类节点
{
公共int Id{get;set;}
public int ParentId{get;set;}
公共字符串名称{get;set;}
}
公共类层次结构节点
{
公共int Id{get;set;}
public int ParentId{get;set;}
公共列表子项{get;set;}
}
从这里,您可以将您的
列表
绑定为第一个组合框的
项源
。然后,您将第二个组合框的
项源
设置为第一个组合框的
子项
属性。在层次结构中添加尽可能多的子项组合框

解决方案2

另一种解决方案是在视图模型中使用
ILookup
,其中
TKey
ParentId
。在
SelectedItem
的绑定属性中,您可以使用该项通过使用该项的
父项为子组合框构建新的
ItemSource