如何在单个Silverlight TreeView节点中拥有多种类型的子节点?

短款:

我必须显示不同类型的项目的层次结构( TreeView ),并且不确定如何在Silverlight中干净地执行此操作。 在WPF中,可以直接根据类型定义模板( HierarchicalDataTemplate ),但Silverlight中不提供此function。 在Silverlight中,您必须将相同的模板应用于特定节点的所有子节点,因此您最终会使用一次单个怪物模板来处理每个可能类型的节点,并应用于每个节点。

长版(带示例):

为了给出一个更具体(但是做作)的例子,考虑各种文件夹中的档案树视图,其中每个档案可以包含照片,歌曲和其他档案。 每个文件夹可能包含多个子文件夹和存档。

 |-Folder |-Folder |-Folder |-Archive | Photo1 | Photo2 | Song1 | Song2 |-Archive | Photo1 | Song1 |-Archive | Photo1 | Photo2 | Photo3 

树中的每种类型(文件夹,存档,照片,乐曲)的显示方式都不同。 显而易见的解决方案似乎是为要显示的每种类型的项创建HierarchicalDataTemplate 。 不幸的是,我找不到一个好方法,因为你似乎必须为一个节点的所有子节点指定一个模板类型( ItemsSource={Binding ...}, ItemsTemplate={StaticResource TemplateForAllChildren} )。

此要求导致模板滚雪球…存档可以将照片,歌曲和档案作为子项。 由于必须将单个模板应用于所有子项,因此该模板必须能够处理照片,歌曲和档案。 同样,文件夹的模板必须能够处理文件夹和档案,而档案模板现在卡在其中的照片和歌曲,所以它最终成为一个可以处理照片,歌曲,档案和文件夹的巨型模板。 随着更多类型的添加,它们也被集中到一个巨大的模板中。

有没有办法干净地完成这项工作,而不会累积一个巨型模板(和相关的节点视图模型),因为不同的类型被添加到树中?

谢谢!

一些澄清:

感谢到目前为止的答案,但我认为他们可能会让我回到最初的问题。 我可能误解了答案。

考虑TreeView显示:

对于歌曲:带有艺术家/标题的滚动文本框和播放按钮

对于图片:缩略图图像和星级评分控件

对于存档:存档图像,其中一个进度条显示压缩

对于文件夹:显示文件夹名称的普通标签

据我所知,实现这一目标的唯一方法是拥有一个包含滚动文本框,播放按钮,缩略图查看器,星形控件,图像控件,进度条和标签的巨型HierarchicalDataTemplate。 然后,我只是选择性地隐藏除了实际应用于节点的一个或两个控件之外的所有控件。

在WPF中,我可以将模板与节点类型相关联,因此每个节点都可以使用适当的模板。 我想知道在Silverlight中是否有办法做到这一点。

再次感谢!

好吧,你为什么不尝试这样的事情呢?

HierarchicalDataTemplate

       

节点类

 public class Node { public string Name { get; set; } public ObservableCollection SubItems { get; set; } public SolidColorBrush ForegroundColor { get; set; } public Node(string name, Color foregroundColor, params Node[] items) { this.Name = name; this.SubItems = new ObservableCollection(items); this.ForegroundColor = new SolidColorBrush(foregroundColor); } } 

示例数据

 public partial class MainPage : UserControl { public ObservableCollection Nodes { get; set; } public MainPage() { InitializeComponent(); this.Nodes = new Node("Root", Colors.Blue, new Node("File1", Colors.Black), new Node("File2", Colors.Black), new Node("Archive1", Colors.Red, new Node("File3", Colors.Magenta), new Node("File4", Colors.Magenta)) ).SubItems; treeView1.DataContext = this; } } 

在您的情况下,也许可以帮助一个接口(例如INode)具有样式节点的所有属性(如ForegroundColor,或其他),将由每种类型的子类(存档,照片,音乐)实现。

希望这可以帮助。

在Silverlight 5中,我们也可以使用隐式数据模板来解决这个问题:

           ...      

由于Silverlight 5仍然不支持自动选择适当的HierarchicalDataTemplate本身,因此根据它的目标类型,我们对所有类型的节点使用单个HierarchicalDataTemplate。 因此,我们仍然需要每个节点视图模型包含相同的Children成员。

我有一个类似的问题,我有一个具有多个节点类型的TreeView,并希望能够根据节点类型选择不同的模板。

最后,我遇到了一个TemplateChooser,并将其与HierarchicalDataTemplates结合使用。 (请原谅代码在VB中的事实)

 Public MustInherit Class TemplateSelector Inherits ContentControl Public MustOverride Function SelectTemplate(item As Object, container As DependencyObject) As DataTemplate Protected Overrides Sub OnContentChanged(oldContent As Object, newContent As Object) MyBase.OnContentChanged(oldContent, newContent) ContentTemplate = SelectTemplate(newContent, Me) End Sub End Class 

然后,我为树视图创建了一个特定的模板选择器,它根据对象类型公开了不同的数据模板。

 Public Class NodeTypeTemplateSelector Inherits TemplateSelector Public Property NodeType1Template As DataTemplate Public Property NodeType2Template As DataTemplate Public Property NodeType3Template As DataTemplate Public Overrides Function SelectTemplate(item As Object, container As System.Windows.DependencyObject) As System.Windows.DataTemplate If item.GetType.Equals(GetType(NodeType1VM)) Then Return NodeType1Template ElseIf item.GetType.Equals(GetType(NodeType2VM)) Then Return NodeType2Template ElseIf item.GetType.Equals(GetType(NodeType3VM)) Then Return NodeType3Template Else Return Nothing End If End Function End Class 

这是我使用的HierarchicalDataTemplate的XAML,它实现了TemplateSelector。

    

然后我当然为各种类型编写了一些hierarchydatatemplate,例如MynodeType1HierarchicalTemplate等等。