WPF TreeView控件样式美化

有粉丝说想看TreeView,今天就来看看它喽。

定义了ViewModel,重写ItemTemplate。

Scroll样式 还是之前 的文章中写的那个:

参见:

WPF自定义ScrollBar样式

先来看一下今天的效果吧:

image

老规矩,废话不多,直接看代码:

新建一个窗口,全部xaml代码如下:

<Window x:Class="WxDemo.TreeViewDemo"
        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:WxDemo"
       x:Name="window"
        mc:Ignorable="d"
        Title="TreeViewDemo" Height="450" Width="800">

    <Window.Resources>
        <local:TreeItemMarginConverter x:Key="TreeViewItemMarginConverter"/>
                <Style x:Key="TreeViewStyle1" TargetType="{x:Type TreeView}">
                    <Setter Property="Background" Value="Transparent"/>
                    <Setter Property="BorderBrush" Value="Gray"/>
                    <Setter Property="BorderThickness" Value="1"/>
                    <Setter Property="Padding" Value="0"/>
                    <Setter Property="Foreground" Value="Black"/>
                    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
                    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
                    <Setter Property="ScrollViewer.PanningMode" Value="Both"/>
                    <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
                    <Setter Property="VerticalContentAlignment" Value="Center"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type TreeView}">
                                <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" 
                                        BorderThickness="{TemplateBinding BorderThickness}"
                                        SnapsToDevicePixels="true">
                                    <ScrollViewer x:Name="_tv_scrollviewer_" Background="{TemplateBinding Background}" 
                                                  CanContentScroll="false" Focusable="false"
                                                  HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
                                                  Padding="{TemplateBinding Padding}" 
                                                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                                  VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}">
                                        <ItemsPresenter/>
                                    </ScrollViewer>
                                </Border>
                                <ControlTemplate.Triggers>
                                    <Trigger Property="IsEnabled" Value="false">
                                        <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                                    </Trigger>
                                    <Trigger Property="VirtualizingPanel.IsVirtualizing" Value="true">
                                        <Setter Property="CanContentScroll" TargetName="_tv_scrollviewer_" Value="true"/>
                                    </Trigger>
                                </ControlTemplate.Triggers>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                    <Style.Triggers>
                        <Trigger Property="VirtualizingPanel.IsVirtualizing" Value="true">
                            <Setter Property="ItemsPanel">
                                <Setter.Value>
                                    <ItemsPanelTemplate>
                                        <VirtualizingStackPanel/>
                                    </ItemsPanelTemplate>
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                    </Style.Triggers>
</Style>
                <Style x:Key="ToggleStyle" TargetType="ToggleButton">
                    <Setter Property="Width" Value="16"/>
                    <Setter Property="Height" Value="16"/>
                    <Setter Property="Focusable" Value="False"/>
                    <Setter Property="IsTabStop" Value="False"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="ToggleButton">
                                <Border>
                                    <Image x:Name="toggleImg" Source="/images/arrow16.png" RenderTransformOrigin="0.5,0.5">
                                        <Image.RenderTransform>
                                            <RotateTransform Angle="-90"/>
                                        </Image.RenderTransform>
                                    </Image>
                                </Border>
                                <ControlTemplate.Triggers>
                                    <Trigger Property="IsChecked" Value="True">
                                        <Setter Property="RenderTransform" TargetName="toggleImg">
                                            <Setter.Value>
                                                <RotateTransform Angle="0"/>
                                            </Setter.Value>
                                        </Setter>
                                    </Trigger>
                                </ControlTemplate.Triggers>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
</Style>
                <Style TargetType="TreeViewItem">
            <Setter Property="FocusVisualStyle" Value="{x:Null}" />
            <Setter Property="Background" Value="Transparent" />
            <Setter Property="Padding" Value="10,0" />
            <Setter Property="BorderThickness" Value="0" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="TreeViewItem">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition MinHeight="23" />
                                <RowDefinition />
                            </Grid.RowDefinitions>
                            <Border x:Name="Bd" CornerRadius="3" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                                <DockPanel LastChildFill="True" Margin="{Binding Converter={StaticResource TreeViewItemMarginConverter}, RelativeSource={RelativeSource TemplatedParent}}">
                                    <ToggleButton x:Name="Expander" ClickMode="Press" DockPanel.Dock="Left"
                                                  IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" 
                                                  Style="{StaticResource ToggleStyle}" />
                                    <ContentPresenter VerticalAlignment="Center" x:Name="PART_Header" ContentSource="Header"    
                                                      SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                                </DockPanel>
                            </Border>
                            <ItemsPresenter x:Name="ItemsHost" Grid.Row="1" />
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True" SourceName="Bd">
                                <Setter Property="Background"  TargetName="Bd" Value="lightGray"/>
                            </Trigger>
                            <Trigger Property="IsExpanded" Value="False">
                                <Setter Property="Visibility" Value="Collapsed" TargetName="ItemsHost"/>
                            </Trigger>
                            <Trigger Property="HasItems" Value="false">
                                <Setter Property="Visibility" TargetName="Expander" Value="Hidden" />
                            </Trigger>
                            <Trigger Property="IsSelected" Value="true">
                                <Setter Property="Background" TargetName="Bd" Value="LightBlue" />
                                <Setter Property="Foreground" Value="White" />
                            </Trigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="IsSelected" Value="true" />
                                    <Condition Property="IsSelectionActive" Value="false" />
                                </MultiTrigger.Conditions>
                                <Setter Property="Background" TargetName="Bd" Value="Transparent" />
                                <Setter Property="Foreground" Value="Black" />
                            </MultiTrigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Foreground" Value="Gray" />
                            </Trigger>  
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
</Style>
    </Window.Resources>
    <Grid>
        <TreeView Margin="5" Width="300" ItemsSource="{Binding Items,ElementName=window}" Style="{DynamicResource TreeViewStyle1}">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                    <TextBlock Text="{Binding DisplayText}"/>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>

    </Grid>
</Window>

窗体后台代码:

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
namespace WxDemo
{
    public partial class TreeViewDemo : Window, INotifyPropertyChanged
    {
        private ObservableCollection<ItemViewModel> _items = new ObservableCollection<ItemViewModel>();
        public ObservableCollection<ItemViewModel> Items
        {
            get { return _items; }
            set
            {
                _items = value;
                OnPropertyChanged(nameof(Items));
            }
        }

        public TreeViewDemo()
        {
            InitializeComponent();
            Items = new ObservableCollection<ItemViewModel>()
            {
                new ItemViewModel
                {
                    DisplayText="中国人",
                    Children=new ObservableCollection<ItemViewModel>
                    {
                        new ItemViewModel{DisplayText="马云"},
                        new ItemViewModel{DisplayText="马化腾"},
                        new ItemViewModel{
                            DisplayText="WPF UI作者",
                            Children=new ObservableCollection<ItemViewModel>(){
                                new ItemViewModel{ DisplayText="身价:100亿"},
                                new ItemViewModel{ DisplayText="老婆数:100个"},
                            }
                        },
                    }
                },
                new ItemViewModel
                {
                    DisplayText="歪果人",
                    Children=new ObservableCollection<ItemViewModel>
                    {
                        new ItemViewModel{DisplayText="乔布斯"},
                        new ItemViewModel{DisplayText="巴菲特"},
                    }
                },
                new ItemViewModel
                {
                    DisplayText="中国人",
                    Children=new ObservableCollection<ItemViewModel>
                    {
                        new ItemViewModel{DisplayText="马云"},
                        new ItemViewModel{DisplayText="马化腾"},
                        new ItemViewModel{DisplayText="WPF UI作者"},
                    }
                },
                new ItemViewModel
                {
                    DisplayText="歪果人",
                    Children=new ObservableCollection<ItemViewModel>
                    {
                        new ItemViewModel{DisplayText="乔布斯"},
                        new ItemViewModel{DisplayText="巴菲特"},
                    }
                },
                new ItemViewModel
                {
                    DisplayText="中国人",
                    Children=new ObservableCollection<ItemViewModel>
                    {
                        new ItemViewModel{DisplayText="马云"},
                        new ItemViewModel{DisplayText="马化腾"},
                        new ItemViewModel{DisplayText="WPF UI作者"},
                    }
                },
                new ItemViewModel
                {
                    DisplayText="歪果人",
                    Children=new ObservableCollection<ItemViewModel>
                    {
                        new ItemViewModel{DisplayText="乔布斯"},
                        new ItemViewModel{DisplayText="巴菲特"},
                    }
                },
                new ItemViewModel
                {
                    DisplayText="中国人",
                    Children=new ObservableCollection<ItemViewModel>
                    {
                        new ItemViewModel{DisplayText="马云"},
                        new ItemViewModel{DisplayText="马化腾"},
                        new ItemViewModel{DisplayText="WPF UI作者"},
                    }
                },
                new ItemViewModel
                {
                    DisplayText="歪果人",
                    Children=new ObservableCollection<ItemViewModel>
                    {
                        new ItemViewModel{DisplayText="乔布斯"},
                        new ItemViewModel{DisplayText="巴菲特"},
                    }
                },
            };
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }
    public class ItemViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
        public string DisplayText { get; set; }
        public ObservableCollection<ItemViewModel> Children { get; set; } = new ObservableCollection<ItemViewModel>();
    }
}

主窗体中使用到了一个转换器:

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;

namespace WxDemo
{
    public class TreeItemMarginConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var left = 0.0;
            UIElement element = value as TreeViewItem;
            while (element != null && element.GetType() != typeof(TreeView))
            {
                element = (UIElement)VisualTreeHelper.GetParent(element);
                if (element is TreeViewItem)
                    left += 18.0;
            }
            return new Thickness(left, 0, 0, 0);
        }

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

TreeView左侧的小箭头是在Iconfont网站下载的,可以自行下载:

image

下载时选择宽度16,黑色就行了。

控件色彩搭配不是很好,你可以自行修改哦,LightBlue和Gray的颜色都在xaml文件里。

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情

    暂无评论内容