—恢复内容开始—

wpf自带的TreeView样式相对比较简单,为了设计符合自己设想中的样式,从头理了一下xmal的样式定义流程。

1、新建ResourceDictionary,便于对自定义样式资源分类、管理

2、编写样式TreeView.xmal

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:i="clr-namespace:WpfTreeView">
    <i:TreeViewLineConverter x:Key="LineConverter"/>

    <!-- Toggle Button -->
    <Style x:Key="ExpandCollapseToggleStyle" TargetType="ToggleButton">
        <Setter Property="Focusable" Value="False"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ToggleButton">
                    <Grid Width="15" Height="13" SnapsToDevicePixels="True">
                        <Rectangle Width="9" Height="9" Stroke="#919191" SnapsToDevicePixels="true">
                            <Rectangle.Fill>
                                <LinearGradientBrush EndPoint="0.5,2" StartPoint="0.5,0">
                                    <GradientStop Color="White" Offset="0"/>
                                    <GradientStop Color="Silver" Offset="0.5"/>
                                    <GradientStop Color="LightGray" Offset="1"/>
                                </LinearGradientBrush>
                            </Rectangle.Fill>
                        </Rectangle>
                        <Rectangle x:Name="ExpandPath" Width="1" Height="5" Stroke="Black" SnapsToDevicePixels="true"/>
                        <Rectangle Width="5" Height="1" Stroke="Black" SnapsToDevicePixels="true"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="True">
                            <Setter Property="Visibility"  TargetName="ExpandPath" Value="Collapsed"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!-- TreeViewItem -->
    <Style x:Key="DefaultTreeViewItem" TargetType="{x:Type TreeViewItem}">
        <Setter Property="IsExpanded" Value="{Binding IsExpanded}" />
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="Padding" Value="1,0,0,0"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TreeViewItem}">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition MinWidth="19" Width="Auto"/>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition/>
                        </Grid.RowDefinitions>

                        <!-- Connecting Lines -->
                        <Rectangle x:Name="HorLn" Margin="9,1,0,0" Height="1" Stroke="#DCDCDC" SnapsToDevicePixels="True"/>
                        <Rectangle x:Name="VerLn" Width="1" Stroke="#DCDCDC" Margin="0,0,1,0" Grid.RowSpan="2" SnapsToDevicePixels="true" Fill="White"/>
                        <ToggleButton Margin="-1,0,0,0" x:Name="Expander" Style="{StaticResource ExpandCollapseToggleStyle}" IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press"/>
                        <Border Name="Bd" Grid.Column="1" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
                            <ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" MinWidth="20"/>
                        </Border>
                        <ItemsPresenter x:Name="ItemsHost" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2"/>
                    </Grid>
                    <ControlTemplate.Triggers>

                        <!-- This trigger changes the connecting lines if the item is the last in the list -->
                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource LineConverter}}" Value="true">
                            <Setter TargetName="VerLn" Property="Height" Value="9"/>
                            <Setter TargetName="VerLn" Property="VerticalAlignment" Value="Top"/>
                        </DataTrigger>
                        <Trigger Property="IsExpanded" Value="false">
                            <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed"/>
                        </Trigger>
                        <Trigger Property="HasItems" Value="false">
                            <Setter TargetName="Expander" Property="Visibility" Value="Hidden"/>
                        </Trigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="HasHeader" Value="false"/>
                                <Condition Property="Width" Value="Auto"/>
                            </MultiTrigger.Conditions>
                            <Setter TargetName="PART_Header" Property="MinWidth" Value="75"/>
                        </MultiTrigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="HasHeader" Value="false"/>
                                <Condition Property="Height" Value="Auto"/>
                            </MultiTrigger.Conditions>
                            <Setter TargetName="PART_Header" Property="MinHeight" Value="19"/>
                        </MultiTrigger>
                        <Trigger Property="IsSelected" Value="true">
                            <Setter TargetName="Bd" Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                        </Trigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsSelected" Value="true"/>
                                <Condition Property="IsSelectionActive" Value="false"/>
                            </MultiTrigger.Conditions>
                            <Setter TargetName="Bd" Property="Background" Value="Green"/>
                            <Setter Property="Foreground" Value="White"/>
                        </MultiTrigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!--TreeView-->
    <Style x:Key="DefaultTreeView" TargetType="{x:Type TreeView}">
        <Setter Property="ScrollViewer.CanContentScroll" Value="True" />
        <Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"></Setter>
        <Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling" />
        <Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False" />
        <Setter Property="ItemContainerStyle" Value="{StaticResource DefaultTreeViewItem}"></Setter>
        <Setter Property="Padding" Value="0"/>
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel IsItemsHost="True" Margin="0"/>
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="ItemTemplate">
            <Setter.Value>
                <HierarchicalDataTemplate  ItemsSource="{Binding Path=Children}">
                    <StackPanel Orientation="Horizontal">
                        <Image VerticalAlignment="Center" Source="{Binding Icon}" Width="16" Height="16" Margin="0,0,2,2"></Image>
                        <TextBlock VerticalAlignment="Center" Name="nodeName" Text="{Binding DisplayName}"></TextBlock>
                        <Image VerticalAlignment="Center" Source="{Binding EditIcon}" Margin="2,0,0,0"></Image>
                        <StackPanel.ToolTip>
                            <TextBlock VerticalAlignment="Center" Text="{Binding TipContents}" TextWrapping="Wrap" MaxWidth="200" ></TextBlock>
                        </StackPanel.ToolTip>
                    </StackPanel>
                </HierarchicalDataTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

3、编写转换器,其中PropertyNodeItem为节点类,TreeViewLineConverter为折叠线条转换器

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Data;

namespace WpfTreeView
{
    /// <summary>
    /// 节点类
    /// </summary>
    internal class PropertyNodeItem
    {
        /// <summary>
        /// 图标
        /// </summary>
        public string Icon { get; set; }
        /// <summary>
        /// 编辑图标
        /// </summary>
        public string EditIcon { get; set; }
        /// <summary>
        /// 名称
        /// </summary>
        public string DisplayName { get; set; }
        /// <summary>
        /// 展示内容
        /// </summary>
        public string TipContents { get; set; }
        /// <summary>
        /// id
        /// </summary>
        public int id { get; set; }
        /// <summary>
        /// 父id
        /// </summary>
        public int parentId { get; set; }
        /// <summary>
        /// 是否展开
        /// </summary>
        public bool IsExpanded { get; set; }
        /// <summary>
        /// 子节点
        /// </summary>
        public List<PropertyNodeItem> Children { get; set; }
        /// <summary>
        /// 构造函数
        /// </summary>
        public PropertyNodeItem()
        {
            Children = new List<PropertyNodeItem>();
        }
    }
    class TreeViewLineConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            TreeViewItem item = (TreeViewItem)value;
            ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item);
            return ic.ItemContainerGenerator.IndexFromContainer(item) == ic.Items.Count - 1;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return false;
        }
    }
}

 

4、在app.xmal中添加对TreeView.xmal的引用

<Application x:Class="WpfTreeView.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="TreeView.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

5、在MainWindow.xmal中添加TreeView

<Window x:Class="WpfTreeView.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="clr-namespace:WpfTreeView"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
    </Window.Resources>
    <Grid>
        <TreeView x:Name="tvProperties" SelectedItemChanged="tvProperties_SelectedItemChanged" Style="{StaticResource DefaultTreeView}">           
        </TreeView>
    </Grid>
</Window>

6、在MainWindow.xmal.cs中添加节点

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfTreeView
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            ShowTreeView();
        }
        private void ShowTreeView()
        {
            List<PropertyNodeItem> list = new List<PropertyNodeItem>();
            PropertyNodeItem node1 = new PropertyNodeItem()
            {
                DisplayName = "测试1",
                Icon = @"\Images\do.png",
                id = 1,
                parentId = 0,
                TipContents = "测试内容,节点1 ",
            };
            PropertyNodeItem node11 = new PropertyNodeItem()
            {
                DisplayName = "测试1子节点1",
                Icon = @"\Images\do.png",
                id = 11,
                parentId = 1,
                TipContents = "测试内容,子节点1 ",
            };
            node1.Children.Add(node11);
            PropertyNodeItem node12 = new PropertyNodeItem()
            {
                DisplayName = "测试1子节点2",
                Icon = @"\Images\do.png",
                id = 12,
                parentId = 1,
                TipContents = "测试内容,子节点2 ",
            };
            node1.Children.Add(node12);
            list.Add(node1);
            PropertyNodeItem node2 = new PropertyNodeItem()
            {
                DisplayName = "测试2",
                Icon = @"\Images\do.png",
                id = 2,
                parentId = 0,
                TipContents = "测试内容,节点2 ",
            };
            list.Add(node2);
            tvProperties.ItemsSource = list;
        }
        //选中节点事件
        private void tvProperties_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            PropertyNodeItem item = this.tvProperties.SelectedItem as PropertyNodeItem;
            string nodeText = item.DisplayName;

            //  MessageBox.Show(nodeText);

        }
    }
}

7、效果

8、总结

  在此样例中,做了简单的效果,对于事件的处理及其它效果需要理解后,根据自己需求添加。

 

版权声明:本文为GanSlide原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/GanSlide/p/10571733.html