如何在TreeView中显示嵌套关系

时间:2014-11-19 05:21:16

标签: wpf treeview hierarchicaldatatemplate

TreeView显示嵌套关系时苦苦挣扎。这是场景:

在数据库中,我有CategoryAccount个表。每个类别可以包含零个或多个子类别,因此该表与自身具有嵌套关系。每个类别/子类别中可以包含零个或多个帐户,CategoryAccount之间存在一对多关系。很简单,不是吗!

在我的数据库之上,我有EDMX,其中包含CategoriesAccounts个实体及其关联,如上所述。为了便于理解,我重命名了导航属性,以便Categories现在具有ParentCategoryChildCategoriesAccounts属性。

在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合作,无法将他的解决方案转换为我的方案。

enter image description here

1 个答案:

答案 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; }
}
}

screenshot of sample app