在TreeView
显示嵌套关系时苦苦挣扎。这是场景:
在数据库中,我有Category
和Account
个表。每个类别可以包含零个或多个子类别,因此该表与自身具有嵌套关系。每个类别/子类别中可以包含零个或多个帐户,Category
和Account
之间存在一对多关系。很简单,不是吗!
在我的数据库之上,我有EDMX,其中包含Categories
和Accounts
个实体及其关联,如上所述。为了便于理解,我重命名了导航属性,以便Categories
现在具有ParentCategory
,ChildCategories
和Accounts
属性。
在EDMX之上,我有我的ViewModel,它定义了一个名为AllCategories
的公共属性。我的TreeView将绑定到此属性。我在启动时初始化此属性,如下所示:
using (MyEntities context = new MyEntities())
Categories = context.Categories.Include(x => x.Accounts).ToList();
最后,我使用以下HierarchicalDataTemplate
来展示这些内容:
<HierarchicalDataTemplate DataType = "{x:Type local:Category}" ItemsSource = "{Binding Path=ChildCategories}">
<TreeViewItem Header="{Binding Name}" ItemsSource="{Binding Accounts}" />
</HierarchicalDataTemplate>
<DataTemplate DataType = "{x:Type local:Account}">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
这样运行正常并显示树中的类别,子类别和帐户,但问题是子类别不仅显示在其父类别下,还显示在根级别。对于所有深度的类别都会发生这种情况。我在这里做错了什么?
注意:如果我在VM中添加.Where(x=>!x.ParentID.HasValue)
,它只会显示根类别及其直接子项,而不会显示其他内容。
这是目前的样子。一切都很好,直到虚线白线(我手动添加该行作为插图;与WPF无关)。之后,子类别开始重复其子子类别。这个过程一直持续到叶子类别。我相信我理解这里发生了什么,但是没有解决方案。作为参考,this guy提供了问题的解决方案,但他正在使用DataSet,而我正在与EF合作,无法将他的解决方案转换为我的方案。
答案 0 :(得分:0)
我们的想法是通过ObservableCollections连接您的业务数据,并使您的Hierarchical模板保持简单,以便树视图不会显示重复的条目。 示例代码显示嵌套的viewmodel关系和相应的分层模板。为简化起见,Root是一个ObservableCollection(否则你需要在这里添加INotifyPropertyChanged和TreeView中的选择性ItemsSource绑定)
<Window x:Class="MyWpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyWpf"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<HierarchicalDataTemplate DataType = "{x:Type local:RootItem}" ItemsSource = "{Binding Path=Categories}">
<TextBlock Text="{Binding Header}"></TextBlock>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType = "{x:Type local:CatNode}" ItemsSource = "{Binding Path=Items}">
<TextBlock Text="{Binding Header}"></TextBlock>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<TreeView ItemsSource="{Binding MyRoot}"/>
</Grid>
</Window>
namespace MyWpf
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
MyRoot = new ObservableCollection<RootItem>();
MyRoot.Add(new RootItem());
}
public ObservableCollection<RootItem> MyRoot { get; set; }
}
public class RootItem
{
public RootItem()
{
Categories = new ObservableCollection<CatNode>();
Categories.Add(new CatNode { Header = "Cat1" });
Categories[0].Items.Add("Item11");
Categories[0].Items.Add("Item12");
Categories.Add(new CatNode { Header = "Cat2" });
Categories[1].Items.Add("Item21");
Categories[1].Items.Add("Item22");
}
public string Header { get { return "Root"; }}
public ObservableCollection<CatNode> Categories { get; set; }
}
public class CatNode
{
public CatNode()
{
Items = new ObservableCollection<string>();
}
public string Header { get; set; }
public ObservableCollection<string> Items { get; set; }
}
}