我有一些代表用户库的类。它们看起来像这样:
public class UserLibraryData
{
public IList<Node<UserDataEntry>> Nodes { get; private set; }
...
}
public class Node<T>
{
public IList<Node<T>> SubNodes { get; private set; }
public IList<T> Entries { get; private set; }
public string Name { get; private set; }
...
}
public class UserDataEntry
{
string ViewName { get; private set;}
...
}
因此它就像一个包含文件夹(节点)和文件(条目)的文件系统。
现在我想在TreeView中表示该数据。我写了一个XAML文件,其实例为UserLibraryData
作为其DataContext。对于TreeView,我写了这个:
<TreeView ItemsSource="{Binding Nodes}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding SubNodes}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
但正如预期的那样,它只显示节点和子节点,而不是条目。我尝试将另一个DataTemplate
添加到TreeViewTemplate
,但似乎我只能定义一个这样的模板。
那么我如何在每一层中显示节点的条目呢?
编辑:
假设我们有以下UserLibraryData:
Node1 -> contains Node2, Node3 and Entry1, Entry2
Node2 -> contains Entry3, Entry4
Node3 -> contains Node4
Node4 -> contains Entry5
Node5 -> contains nothing
这是我的预期输出(扩展所有节点时):
Node1
Node2
Entry3
Entry4
Node3
Node4
Entry5
Entry1
Entry2
Node5
EDIT2:
如果Node
类不是通用的,那么这个答案https://stackoverflow.com/a/39721198/5333340就可以解决我的问题。不幸的是,正如我从其他SO线程中学到的那样,DataType="{x:Type ...}"
不允许泛型类型。一个常见的解决方法是创建一个像这样的子类
public class NodeUserDataEntry : Node<UserDataEntry> { ... }
然后将Node<UserDataEntry>
的每次出现替换为NodeUserDataEntry
。但是,已经编写了大量代码,这些代码大量使用了Node
的通用性。因此,将类型从Node<UserDataEntry>
更改为NodeUserDataEntry
就像重新编写整个应用程序一样。是不是还有另一种方法可以保留我已编写的UserLibraryData
,Node<T>
和UserDataEntry
代码,只是扩展它,可能是通过某些转换器/包装器?
答案 0 :(得分:1)
我采用了你的数据结构并添加了一些缺失的东西,以便它能够正常工作。
您的问题如下......
在构建HierarchicalDataTemplate
时,您无法选择两个列表ItemsSource
。因此,您无法告诉您的模板显示SubNodes
中的Entries
和Node
。
为了能够构建TreeView
,您必须构建一个包含List
和Entries
对象的唯一SubNodes
。
我称之为Childrens
。 (在节点类中添加它。)
public List<object> Childrens
{
get
{
_childrens = new List<object>();
foreach (var subNode in SubNodes)
{
_childrens.Add(subNode);
}
foreach (var userDataEntry in Entries)
{
_childrens.Add(userDataEntry);
}
return _childrens;
}
private set { _childrens = value; }
}
在此之后你必须改变你的XAML。
我将模板声明为ressources,并且由于DataTypes
,模板将在运行时解析。
我们希望展示:
Name
的Node
。ViewName
的Entry
。Subnodes
的{{1}}媒体资源中包含 Entries
和Childrens
。 (这揭示了以前的两个属性)。
Node
假设您的DataContext设置为Class UserLibraryData,您必须以这种方式声明TreeView:
<Grid.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Node}" ItemsSource="{Binding Childrens}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:UserDataEntry}">
<TextBlock Text="{Binding ViewName}"/>
</DataTemplate>
</Grid.Resources>
你应该得到这个结果:
答案 1 :(得分:0)
我找到了另一种解决方法:
按照https://stackoverflow.com/a/39721198/5333340的建议将Childrens
属性添加到课程Node<T>
。
将班级ViewName
的媒体资源UserDataEntry
重命名为Name
。
将ItemsSource
的{{1}}更改为HierarchicalDataTemplate
由于我的XAML代码中的"{Binding Childrens}"
没有设置HierarchicalDataTemplate
属性,因此它用于DataType
集合的所有元素(Childrens
和{{ 1}}),因为它们都具有属性Node<T>
,所以它们都显示出来。
这比在代码中的各处更改类型要容易得多。
但我仍然感兴趣的是一个解决方案,我不需要更改已有的代码,只需要扩展它。