简单的嵌套 TreeView Xaml 结构?

Posted

技术标签:

【中文标题】简单的嵌套 TreeView Xaml 结构?【英文标题】:Simple Nested TreeView Xaml structure? 【发布时间】:2015-05-13 15:39:54 【问题描述】:

我正在尝试构建一个具有三层的 WPF TreeViewCountryReportTitle 是一个字符串属性,ArticleCategoryTitlesList 是一个集合,两者都暴露于我的ViewModel。没有定义类层次结构。这是我正在寻找的结构:

这是我尝试的 Xaml,但我在运行时在 Xaml 中遇到异常:

"Item has already been added. Key in dictionary: 'DataTemplateKey(ISESApp.ViewModels.ReportViewModel)'  Key being added: 'DataTemplateKey(ISESApp.ViewModels.ReportViewModel)'"

Xaml:

       <TreeView ItemsSource="Binding CountryReportTitle">
                    <TreeView ItemsSource="Binding CountryReportTitle">
                        <TreeView.Resources>
                            <HierarchicalDataTemplate  DataType="x:Type local:ReportViewModel"
                                ItemsSource="Binding ArticleCategoryTitlesList">
                                <TextBlock Text="Binding CategoryTitle" />
                            </HierarchicalDataTemplate>
                            <HierarchicalDataTemplate  DataType="x:Type local:ReportViewModel"
                                ItemsSource="Binding ArticleCatagoryTypesList">
                                <TextBlock Text="Binding ArticleTitle" />
                            </HierarchicalDataTemplate>
                            <DataTemplate  DataType="x:Type local:ReportViewModel">
                                <TextBlock Text="Binding ArticleTitle" />
                            </DataTemplate>
                        </TreeView.Resources>
                    </TreeView>
                </TreeView>

Local: 是我的 ViewModel 的命名空间:

xmlns:local="clr-namespace:MyApp.ViewModels"

我做错了什么,解决这个问题的最佳方法是什么?

【问题讨论】:

【参考方案1】:

这是树视图的首选示例。

对树中的元素使用HierarchicalDataTemplate。请注意,共有三层,每一层都有自己的类型。这是为了方便起见,但您可以为树定义一种类型并使用一个模板或任何类型的组合。不同的类型代表树中的不同事物,使用模板非常方便。

数据类

public class ViewModel

    public ObservableCollection<ItemA> ItemsA  get; set; 
    public ViewModel()
    
        ItemsA = new ObservableCollection<ItemA>(new[]
            new ItemAName = "A one",
            new ItemAName = "A Two",
            new ItemAName = "A Three",
        );
    


public class ItemA

    public ObservableCollection<ItemB> ItemsB  get; set; 
    public string Name  get; set; 
    public ItemA()
    
        ItemsB = new ObservableCollection<ItemB>(new[]
            new ItemBName = "B one",
            new ItemBName = "B Two",
            new ItemBName = "B Three",
        );
    

public class ItemB

    public ObservableCollection<ItemC> ItemsC  get; set; 
    public string Name  get; set; 
    public ItemB()
    
        ItemsC = new ObservableCollection<ItemC>(new[]
            new ItemCName = "C one",
            new ItemCName = "C Two",
            new ItemCName = "C Three",
        );
    

public class ItemC

    public string Name  get; set; 

还有用户界面

 <TreeView ItemsSource="Binding ItemsA">
    <TreeView.Resources>
        <HierarchicalDataTemplate  DataType="x:Type t:ItemA"
                                    ItemsSource="Binding ItemsB">
            <TextBlock Text="Binding Name" />
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate  DataType="x:Type t:ItemB"
                                    ItemsSource="Binding ItemsC">
            <TextBlock Text="Binding Name" />
        </HierarchicalDataTemplate>
        <DataTemplate  DataType="x:Type t:ItemC">
            <TextBlock Text="Binding Name" />
        </DataTemplate>
    </TreeView.Resources>
</TreeView>

给你一个简单的树视图

【讨论】:

谢谢。我的两个收藏都在同一个 viewModel 中。我真的不想分成不同的班级。如果是这样,我将如何定义 DataType? @Hardgraf 假设 ItemsB 在 ViewModel 上而不是在 ItemA 中。您必须为 ItemA 绑定回 HierarchicalDataTemplate 中的 ViewModel--ItemsSource="Binding DataContext.ItemsB, ElementName=root",确保为您的 Window 提供x:Name="root",以便 ElementName 指向正确的位置。 觉得我快到了。将问题更改为我的新 Xaml,但仍不确定如何为我的每个 HierarchicalDataTemplates 引用正确的 DataTypes。 @Hardgraf 我不知道。从你的问题中不清楚发生了什么。你说事情是错的,但你没有提供关于它是如何出错的信息,如果有错误,等等。 公平点。我当前的代码在问题中。问题是直到运行时我才知道每个列表将包含什么,因此 TreeView 需要在运行时动态构建。我认为我的问题是我设置 DataType- DataType="x:Type local:ReportViewModel" 我不认为这是正确的,但我不确定如何将每个 HierarchicalDataTemplate 绑定到正确的列表中视图模型【参考方案2】:

您需要在 TreeView 中绑定 TreeView 资源:

<TreeView.Resources>
    <HierarchicalDataTemplate
        DataType="x:Type local:FirstLayer"
        ItemsSource="Binding Children">
        <StackPanel Orientation="Horizontal" Margin="2">
            <TextBlock Text="Binding ChildrenName" />
        </StackPanel>
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate
        DataType="x:Type local:SecondLayer"
        ItemsSource="Binding Children">
        <StackPanel Orientation="Horizontal" Margin="2">
            <TextBlock Text="Binding ChildrenName" />
        </StackPanel>
    </HierarchicalDataTemplate>
</TreeView.Resources>

我认为您需要修改项目以将 Treeview 与 ViewModel 绑定,而不是字符串列表

这是一个很好的Example

【讨论】:

以上是关于简单的嵌套 TreeView Xaml 结构?的主要内容,如果未能解决你的问题,请参考以下文章

WPF TreeView绑定xaml的写法(转)

TreeView ItemSsource 绑定到 ViewModel 不更新 xaml 控件项

如何在 Xaml 中使用 SortDescriptions 对 TreeView 项目进行排序?

使用treeview.js插件生成树状菜单方法的简单介绍(附通过json字符串生成菜单的代码)

Wpf Xaml - TreeView 分层数据模板 - 多个项目源

wpf如何将一个TreeView绑定到另一个TreeView