[英]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.