繁体   English   中英

如何绑定分层列表<t>至 WPF TreeView</t>

[英]How to bind hierarchical list<T> to WPF TreeView

我有一个分层类型Category ,我想将其放入TreeView 嵌套级别计数是无限的。 数据存储在带有hierarchyid字段的 DB 中。

Class 定义

public class Category
{
    public Category()
    {
        NestedCategories = new List<Category>();
    }

    public string CategoryParentID { get; set; }
    public string CategoryHID { get; set; }
    public int CategoryID { get; set; }
    public string CategoryName { get; set; }
    public string CategoryValueType { get; set; }
    public DateTime LastTimeUsed { get; set; }

    public List<Category> NestedCategories
    {
        get; set;
    }

    public void AddChild(Category cat)
    {
        NestedCategories.Add(cat);
    }

    public void RemoveChild(Category cat)
    {
        NestedCategories.Remove(cat);
    }

    public List<Category> GetAllChild()
    {
        return NestedCategories;
    }
}

首先,我从表中取出所有数据并将其放入结构化列表中。 我在调试器中检查了结果,它实际上包含了所有级别的类别。

public CategorySelector()
{
    InitializeComponent();
    catctrl = new CategoryController();

    Categories = CategoriesExpanded();

    DataContext = this;
}

private readonly CategoryController catctrl;

public List<Category> Categories { get; set; }

private List<Category> CategoriesExpanded()
{
    List <Category> list = catctrl.GetAllCategories();
    foreach (Category cvo in GetAllCat(list))
    {
        foreach (Category newparent in GetAllCat(list))
        {
            if (newparent.CategoryHID.ToString().Equals(cvo.CategoryParentID.ToString()))
            {
                list.Remove(cvo);
                newparent.AddChild(cvo);
                break;
            }
        }
    }
    return list;
}

private List<Category> GetAllCat(List<Category> list)
{
    List<Category> result = new List<Category>();
    foreach (Category child in list)
    {
        result.AddRange(GetNestedCat(child));
    }
    return result;
}

private List<Category> GetNestedCat(Category cat)
{
    List<Category> result = new List<Category>();
    result.Add(cat);
    foreach (Category child in cat.NestedCategories)
    {
        result.AddRange(GetNestedCat(child));
    }
    return result;
}

然后我在 XAML 中添加绑定,就出现了问题。 我尝试了不同的组合,但我得到的只是第一级显示。

<mah:MetroWindow x:Class="appname.Views.CategorySelector"
        xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:localmodels="clr-namespace:appname.Models"
                 mc:Ignorable="d"
        .....
        <TreeView Name="TV_Categories" Grid.Row="5" FontSize="16" ItemsSource="{Binding Categories}" DisplayMemberPath="CategoryName">
            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type localmodels:Category}" ItemsSource="{Binding NestedCategories}" >
                    <TextBlock Text="{Binding CategoryName}" />
                </HierarchicalDataTemplate>
            </TreeView.Resources>
        </TreeView>
    </Grid>
</mah:MetroWindow>

那么我做错了什么? 谢谢你。

我认为您使用了错误的 XAML 语言版本。 多个XAML 语言版本。 WPF 仅完全支持2006版本。 仅部分支持2009版本。

在 WPF 中,您可以使用 XAML 2009 功能,但仅限于 XAML 不是 Z3055DD7231D79EAA4E0989FDA 标记。 标记编译的 XAML 和 BAML 形式的 XAML 目前不支持 XAML 2009 语言关键字和功能。

这些是正确的2006 年语言 XML 命名空间:

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

在您的DataType定义中,您在属性元素上使用xmlns ,这是2009 年的语言功能

XAML 2009 可以支持属性元素上的 XAML 命名空间(xmlns)定义; 但是,XAML 2006 仅支持 object 元素上的 xmlns 定义。

如果您的项目不符合上述限制条件,则不能在 WPF 中使用它。 相反,您可以在 object 元素上声明您的本地 XML 命名空间,例如您的顶级元素(此处Window )并使用例如:“ x:Type标记DataType="localmodels:Category"

<Window x:Class="YourApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:localmodels="clr-namespace:YourApp"
<HierarchicalDataTemplate DataType="{x:Type localmodels:Category}" ItemsSource="{Binding NestedCategories}" >
   <TextBlock Text="{Binding CategoryName}" />
</HierarchicalDataTemplate>

更新,我找到了根本原因。 如果设置DisplayMemberPath ,这将导致TreeView应用仅显示相应属性值的ToString()文本的数据模板。 不知道您嵌套的 collections 类别。

现在,如果除了设置DisplayMemberPath之外,您还直接将数据模板分配给TreeView.ItemTemplate ,您将收到一个异常,指出您不能同时使用两者。

System.InvalidOperationException:'不能同时设置“DisplayMemberPath”和“ItemTemplate”。'

但是,如果您在Resources中定义数据模板,也不例外,它会静默失败并应用DisplayMemberPath模板,这就是为什么只显示一个级别的原因。

为了解决这个问题,只需删除DisplayMemberPath ,所有这些变体都可以工作。

<TreeView Name="TV_Categories" Grid.Row="5" FontSize="16" ItemsSource="{Binding Categories}">
   <TreeView.Resources>
      <HierarchicalDataTemplate DataType="{x:Type local:Category}" ItemsSource="{Binding NestedCategories}" >
         <TextBlock Text="{Binding CategoryName}" />
      </HierarchicalDataTemplate>
   </TreeView.Resources>
</TreeView>
<TreeView Name="TV_Categories" Grid.Row="5" FontSize="16" ItemsSource="{Binding Categories}">
   <TreeView.ItemTemplate>
      <HierarchicalDataTemplate DataType="{x:Type local:Category}" ItemsSource="{Binding NestedCategories}" >
         <TextBlock Text="{Binding CategoryName}" />
      </HierarchicalDataTemplate>
   </TreeView.ItemTemplate>
</TreeView>
<TreeView Name="TV_Categories" Grid.Row="5" FontSize="16" ItemsSource="{Binding Categories}">
 <TreeView.ItemTemplate>
      <HierarchicalDataTemplate ItemsSource="{Binding NestedCategories}" >
         <TextBlock Text="{Binding CategoryName}" />
      </HierarchicalDataTemplate>
   </TreeView.ItemTemplate>
</TreeView>

终于在这里找到了解决方案 - TreeView 具有多个级别但相同的 object 类型

应该这样做:

<TreeView Name="TV_Categories" Grid.Row="5" FontSize="16" ItemsSource="{Binding Categories}">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding NestedCategories}">
            <TextBlock Text="{Binding CategoryName}"/>
        </HierarchicalDataTemplate>
     </TreeView.ItemTemplate>
</TreeView>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM