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

时间:2010-11-30 20:25:34

标签: c# silverlight xaml treeview hierarchicaldatatemplate

Short Vesion:

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

长版(带示例):

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

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

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

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

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

谢谢!

一些澄清:

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

考虑TreeView显示:

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

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

For Archives:存档图像,进度条显示压缩

对于文件夹:显示文件夹名称

的普通标签

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

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

再次感谢!

3 个答案:

答案 0 :(得分:3)

那么,你为什么不尝试这样的事情?

HierarchicalDataTemplate

<sdk:HierarchicalDataTemplate x:Key="ChildTemplate" ItemsSource="{Binding Path=SubItems}">
    <TextBlock Text="{Binding Name}" Foreground="{Binding ForegroundColor}" />
</sdk:HierarchicalDataTemplate>
<sdk:HierarchicalDataTemplate x:Key="FilesDataTemplate" ItemsSource="{Binding Path=SubItems}" ItemTemplate="{StaticResource ChildTemplate}">
    <TextBlock Text="{Binding Name}" Foreground="{Binding ForegroundColor}" />
</sdk:HierarchicalDataTemplate>

节点类

public class Node
{
    public string Name { get; set; }
    public ObservableCollection<Node> SubItems { get; set; }
    public SolidColorBrush ForegroundColor { get; set; }

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

示例数据

public partial class MainPage : UserControl
{
    public ObservableCollection<Node> 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或其他),这些属性将由每种类型的子类(存档,照片,音乐)实现。

希望这有帮助。

答案 1 :(得分:0)

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

<UserControl.Resources>
    <sdk:HierarchicalDataTemplate x:Key="treeNodeTemplate" 
                                  ItemsSource="{Binding Children}">
        <ContentControl Content="{Binding}">
            <ContentControl.Resources>
                <DataTemplate DataType="ViewModels:Folder">
                    <TextBlock Text="{Binding FolderName}" />
                </DataTemplate>
                <DataTemplate DataType="ViewModels:Song">
                    <Image Source="{Binding PictureSource}" />
                </DataTemplate>
                ...
            </ContentControl.Resources>
        </ContentControl>
    </sdk:HierarchicalDataTemplate>
</UserControl.Resources>

<sdk:TreeView ItemsSource="{Binding Roots, Mode=OneWay}"
              ItemTemplate="{StaticResource treeNodeTemplate}"/>

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

答案 2 :(得分:0)

我遇到了类似的问题,我有一个包含多种节点类型的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。

<sdk:HierarchicalDataTemplate x:Key="SelectingTemplate" ItemsSource="{Binding children, Mode=OneWay}">
            <local:NodeTypeTemplateSelector Content="{Binding}"
                                            NodeType1Template="{StaticResource MyNodeType1HierarchicalTemplate}"
                                            NodeType2Template="{StaticResource MyNodeType2HierarchicalTemplate}"
                                            NodeType3Template="{StaticResource MyNodeType3HierarchicalTemplate}"
                                           />
        </sdk:HierarchicalDataTemplate>
然后,我当然为各种类型制作了一些分层数据,例如: MynodeType1HierarchicalTemplate等等。