簡體   English   中英

如何為 TreeView 項目重用 XAML 模板?

[英]How can I reuse XAML templates for TreeView items?

在下面的示例代碼中,我有一個顯示兩種類型的 WPF 樹視圖。 它工作得很好。 但是,除了使用的圖像文件之外,為每種類型定義模板的 XAML 非常相似。 我怎樣才能擺脫重復? 我假設有一種方法可以單獨定義模板並使用某種觸發器或其他東西來驅動要顯示的圖像。

<Window x:Class="Test.MainWindow"
        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:local="clr-namespace:Test"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <TreeView Name="treeView" HorizontalAlignment="Left" Height="400" Margin="10,10,0,0" VerticalAlignment="Top" 
                  Width="233">
            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type local:TreeFolder}" ItemsSource="{Binding Nodes}">
                    <StackPanel Orientation="Horizontal" Margin="1,2,2,2">
                        <Image Source="images/folder.png" Width="13" Height="13" Margin="0,0,4,0"/>
                        <TextBlock Name="nameTextBlock" Text="{Binding Name}" />
                    </StackPanel>
                </HierarchicalDataTemplate>
                <DataTemplate DataType="{x:Type local:TreeNode}">
                    <StackPanel Orientation="Horizontal" Margin="1,2,2,2">
                        <Image Source="images/subroutine.png" Width="13" Height="13" Margin="0,0,4,0"/>
                        <TextBlock Name="nameTextBlock" Text="{Binding Name}" />
                    </StackPanel>
                </DataTemplate>
            </TreeView.Resources>
        </TreeView>
    </Grid>
</Window>
using System.Collections.ObjectModel;
using System.Windows;

namespace Test
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private readonly ObservableCollection<TreeNode> treeList  = new ObservableCollection<TreeNode>();

        public MainWindow()
        {
            InitializeComponent();

            // set up test data
            treeList.Add(new TreeNode { Name = "Node 1" });
            treeList.Add(new TreeNode { Name = "Node 2" });
            var folder = new TreeFolder { Name = "Folder Node 1" };
            folder.Nodes.Add(new TreeNode { Name = "Node 3" });
            folder.Nodes.Add(new TreeNode { Name = "Node 4" });
            treeList.Add(folder);
            folder = new TreeFolder { Name = "Folder Node 2" };
            folder.Nodes.Add(new TreeNode { Name = "Node 3" });
            treeList.Add(folder);

            treeView.ItemsSource = treeList;
        }
    }
}
namespace Test
{
    public class TreeNode
    {
        public string Name { get; set; }
    }
}
using System.Collections.ObjectModel;

namespace Test
{
    class TreeFolder : TreeNode
    {
        public ObservableCollection<TreeNode> Nodes { get; } = new ObservableCollection<TreeNode>();
    }
}

雖然使用轉換器的解決方案是可能的,但我寧願更改數據結構。 我不認為 TreeFolder 類型是必要的

public enum NodeTypes
{
    Subroutine,
    Folder
}

public class TreeNode
{
    public string Name { get; set; }

    public NodeTypes NodeType { get; set; }

    public ObservableCollection<TreeNode> Nodes { get; } = new ObservableCollection<TreeNode>();
}

然后模板可以更改為:

<HierarchicalDataTemplate DataType="{x:Type local:TreeNode}" ItemsSource="{Binding Nodes}">
    <StackPanel Orientation="Horizontal" Margin="1,2,2,2">

        <Image Width="13" Height="13" Margin="0,0,4,0">
            <Image.Style>
                <Style TargetType="Image">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Path=NodeType}" Value="Folder">
                            <Setter Property="Source" Value="images/folder.png"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding Path=NodeType}" Value="Subroutine">
                            <Setter Property="Source" Value="images/subroutine.png"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Image.Style>
        </Image>

        <TextBlock Name="nameTextBlock" Text="{Binding Name}" />
    </StackPanel>
</HierarchicalDataTemplate>

如果為 Image.Source 創建轉換器,則可以為 TreeNode 和 TreeFolder 重用模板:

public class NodeIconConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is TreeFolder)
        {
            return new BitmapImage(new Uri("/images/folder.png", UriKind.Relative));
        }

        if (value is TreeNode)
        {
            return new BitmapImage(new Uri("/images/subroutine.png", UriKind.Relative));
        }

        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

在視圖資源中添加轉換器:

<Window.Resources>
    <local:NodeIconConverter x:Key="IconConverter"/>
</Window.Resources>

和 mpdify 模板:

<TreeView.ItemTemplate>
    <HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
        <StackPanel Orientation="Horizontal" Margin="1,2,2,2">
            <Image Source="{Binding Converter={StaticResource IconConverter}}" 
                   Width="13" Height="13" Margin="0,0,4,0"/>
            <TextBlock Name="nameTextBlock" Text="{Binding Name}" />
        </StackPanel>
    </HierarchicalDataTemplate>
</TreeView.ItemTemplate>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM