<pre name="code" class="csharp">
一、先看一下运行后的TreeView
备注:以上所有节点全部是后台添加的数据结构节点、不是控件。
二、TreeView样式 、我是自己封装成了控件、所以样式是针对数据结构定义的
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Local="clr-namespace:DialogEx.Controls"
xmlns:Cvt="clr-namespace:DialogEx.Converters"
>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../../Resource/Style/ScrollViewerEx.xaml"/>
</ResourceDictionary.MergedDictionaries>
<LinearGradientBrush x:Key="CheckBackground" StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Color="#098ED4" Offset="0.100"/>
<GradientStop Color="#0D83C7" Offset="0.500"/>
<GradientStop Color="#176CAA" Offset="0.900"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="MouseOverColor">#E5EEC4</SolidColorBrush>
<SolidColorBrush x:Key="LostFocusColor">#E5EEC4</SolidColorBrush>
<Style TargetType="ToggleButton" x:Key="ExpandButtonStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border BorderThickness="0" Background="Transparent">
<Path Name="ExpandedPath" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5" Stroke="#A8A8A8" StrokeThickness="2"></Path>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="ExpandedPath" Property="Data" Value="M0,5 L10,5 M5,0 L5,10"></Setter>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="ExpandedPath" Property="Data" Value="M0,5 L10,5"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="TreeViewItem" x:Key="TreeViewItemStyle">
<!--是否展开-->
<Setter Property="IsSelected" Value="{Binding IsSelected,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"></Setter>
<Setter Property="IsExpanded" Value="{Binding IsExpanded,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"></Setter>
<!--样式-->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeViewItem">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<!--不能直接赋值Background 否则没效果-->
<Border Name="Part_Border" BorderBrush="#E9E9E9" BorderThickness="1" CornerRadius="1" Panel.ZIndex="100" Margin="0,0.8,0,0.8">
<Border.Resources>
<Style TargetType="Border">
<Setter Property="Background" Value="{Binding LevelColor}"></Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource MouseOverColor}"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</Border.Resources>
<StackPanel Orientation="Horizontal">
<ToggleButton Visibility="Hidden" Name="ExpandedPath" Style="{DynamicResource ExpandButtonStyle}" Height="23" Width="23" IsChecked="{Binding IsExpanded,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"></ToggleButton>
<TextBlock Margin="5,0,0,0" Name="DisPlayName" VerticalAlignment="Center" Text="{Binding DisplayName}"></TextBlock>
</StackPanel>
</Border>
<StackPanel Name="Part_Host" IsItemsHost="True" Grid.Row="1" Margin="10,0.6,0,0.6">
</StackPanel>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="False">
<Setter TargetName="Part_Host" Property="Visibility" Value="Collapsed"></Setter>
</Trigger>
<Trigger Property="HasItems" Value="True">
<Setter TargetName="ExpandedPath" Property="Visibility" Value="Visible"></Setter>
</Trigger>
<!--这个触发器会触发父控件、及本子控件的效果-->
<!--<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Part_Border" Property="Background" Value="{DynamicResource MouseOverColor}"></Setter>
</Trigger>-->
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Part_Border" Property="Background" Value="{DynamicResource CheckBackground}"></Setter>
<Setter TargetName="DisPlayName" Property="Foreground" Value="White"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="TreeView" x:Key="TreeViewStyle">
<Setter Property="ItemContainerStyle" Value="{DynamicResource TreeViewItemStyle}"></Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<HierarchicalDataTemplate ItemsSource="{Binding Children}" ItemContainerStyle="{StaticResource TreeViewItemStyle}">
</HierarchicalDataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeView}">
<Grid>
<Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{x:Null}" BorderThickness="0" CornerRadius="1,1,1,1">
<ScrollViewer Margin="0,2,0,2" Style="{StaticResource ScrollViewerStyle}" Focusable="False" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" CanContentScroll="False" Foreground="{DynamicResource {x:Static SystemColors.ActiveCaptionTextBrushKey}}">
<ItemsPresenter Margin="2" />
</ScrollViewer>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
三、封装自定义控件加载TreeView样式
using DialogEx.Classes;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace DialogEx.Controls
{
public class TreeViewEx : TreeView
{
#region 公共方法
//构造
public TreeViewEx()
{
Loaded += (sender, args) =>
{
this.Resources = ResourceDictionaries.ResourceCollection_TreeViewEx;
this.Style = this.Resources["TreeViewStyle"] as Style;
};
}
#endregion
public class TreeViewExNode : INotifyPropertyChanged
{
#region private
private string _DisplayName = "";
private bool _IsExpanded = false;
private int _Level = 1;
private string _ID;
private TreeViewExNode _Parent;
#endregion
public event PropertyChangedEventHandler PropertyChanged;
#region 公共属性
public string ID
{
get { return _ID; }
set { this._ID = value; RaisePropertyChanged("ID"); }
}
public TreeViewExNode Parent
{
get { return this._Parent; }
set
{
if (this._Parent != null)
{
throw new Exception("同一个节点只能指定一次父节点");
}
else
{
this._Parent = value;
}
}
}
/// <summary>
/// 展示名称
/// </summary>
public string DisplayName
{
get { return this._DisplayName; }
set { this._DisplayName = value; RaisePropertyChanged("DisplayName"); }
}
/// <summary>
/// 是否展开
/// </summary>
public bool IsExpanded
{
get { return this._IsExpanded; }
set
{
if (this._IsExpanded != value)
{
this._IsExpanded = value;
RaisePropertyChanged("IsExpanded");
}
}
}
private bool _IsSelected;
public bool IsSelected
{
get { return _IsSelected; }
set { _IsSelected = value; }
}
/// <summary>
/// 层级 >= 1
/// </summary>
public int Level
{
get { return this._Level; }
set
{
this._Level = value;
}
}
/// <summary>
/// Level颜色
/// </summary>
public LinearGradientBrush LevelColor
{
get
{
LinearGradientBrush levelColor = null;
switch (Level)
{
case 1: { levelColor = ResourceDictionaries.ResourceCollection_Colors["TreeViewExLevel01Color"] as LinearGradientBrush; } break;
case 2: { levelColor = ResourceDictionaries.ResourceCollection_Colors["TreeViewExLevel02Color"] as LinearGradientBrush; } break;
case 3: { levelColor = ResourceDictionaries.ResourceCollection_Colors["TreeViewExLevel03Color"] as LinearGradientBrush; } break;
}
return levelColor;
}
}
/// <summary>
/// 子列表
/// </summary>
public ObservableCollection<TreeViewExNode> Children { get; set; }
#endregion
#region 公共方法
//构造
public TreeViewExNode()
{
Children = new ObservableCollection<TreeViewExNode>();
}
//通知
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
};
}
}
备注:其中有一个类ResourceDictionaries是个静态的资源字典,目的是无论新建多少该TreeView 实例始终加载同一个资源
ResourceDictionaries.ResourceCollection_TreeViewEx是这么定义的
/// <summary>
/// 颜色字典
/// </summary>
public static ResourceDictionary ResourceCollection_Colors
{
get
{
if (_ResourceCollection_Colors == null)
{
_ResourceCollection_Colors = new ResourceDictionary();
_ResourceCollection_Colors.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("DialogEx;Component/Resource/Colors/Colors.xaml", UriKind.RelativeOrAbsolute) });
}
return _ResourceCollection_Colors;
}
}
/// <summary>
/// TreeViewEx资源-定义样式加载器
/// </summary>
public static ResourceDictionary ResourceCollection_TreeViewEx
{
get
{
if (_ResourceCollection_TreeViewEx == null)
{
_ResourceCollection_TreeViewEx = new ResourceDictionary();
_ResourceCollection_TreeViewEx.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("DialogEx;Component/Controls/TreeViewEx/TreeViewEx.xaml", UriKind.RelativeOrAbsolute) });
}
return _ResourceCollection_TreeViewEx;
}
}
颜色资源:层级颜色是通过 Level来设置的请看节点数据结构的代码、目前颜色字典里仅仅设置了前3级颜色。
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!--TreeViewEx层级1颜色-->
<LinearGradientBrush x:Key="TreeViewExLevel01Color" StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Color="#FDFDFD" Offset="0.100"/>
<GradientStop Color="#F4F4F4" Offset="0.500"/>
<GradientStop Color="#EEEEEE" Offset="0.900"/>
</LinearGradientBrush>
<!--TreeViewEx层级2颜色-->
<LinearGradientBrush x:Key="TreeViewExLevel02Color" StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Color="#D1EDFF" Offset="0.100"/>
<GradientStop Color="#D1EDFF" Offset="0.500"/>
<GradientStop Color="#D1EDFF" Offset="0.900"/>
</LinearGradientBrush>
<!--TreeViewEx层级3颜色-->
<LinearGradientBrush x:Key="TreeViewExLevel03Color" StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Color="#26A0B0" Offset="0.100"/>
<GradientStop Color="#2E8E9A" Offset="0.500"/>
<GradientStop Color="#348189" Offset="0.900"/>
</LinearGradientBrush>
</ResourceDictionary>
四、调用TreeView - 直接在调用窗口Window.xaml加载本控件
1、前台XAML
<Window x:Class="WPFPro.Views.TreeViewExView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TreeViewExView" Height="600" Width="900"
xmlns:TreeViewExSpace="clr-namespace:ExpControls.Conrols;assembly=ExpControls"
>
<Grid>
<TreeViewExSpace:TreeViewEx ItemsSource="{Binding ModelList}">
</TreeViewExSpace:TreeViewEx>
</Grid>
</Window>
2、后台CS
using ExpControls.Conrols;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
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.Shapes;
namespace WPFPro.Views
{
/// <summary>
/// TreeViewExView.xaml 的交互逻辑
/// </summary>
public partial class TreeViewExView : Window
{
public TreeViewExView()
{
InitializeComponent();
this.ModelList = new ObservableCollection<TreeViewEx.TreeViewExNode>();
TreeViewEx.TreeViewExNode Node = new TreeViewEx.TreeViewExNode()
{
IsExpanded = true,
Level = 1,
DisplayName = "节点1"
};
Node.Children.Add(new TreeViewEx.TreeViewExNode() { IsExpanded = false, Level = 2, DisplayName = "节点101" });
Node.Children.Add(new TreeViewEx.TreeViewExNode() { IsExpanded = false, Level = 2, DisplayName = "节点102" });
TreeViewEx.TreeViewExNode Node103 = new TreeViewEx.TreeViewExNode() { IsExpanded = false, Level = 2, DisplayName = "节点103" };
Node103.Children.Add(new TreeViewEx.TreeViewExNode() { IsExpanded = false, Level = 3, DisplayName = "节点103-001" });
Node.Children.Add(Node103);
ModelList.Add(Node);
Node = new TreeViewEx.TreeViewExNode()
{
IsExpanded = true,
Level = 1,
DisplayName = "节点2"
};
Node.Children.Add(new TreeViewEx.TreeViewExNode() { IsExpanded = false, Level = 2, DisplayName = "节点201" });
Node.Children.Add(new TreeViewEx.TreeViewExNode() { IsExpanded = false, Level = 2, DisplayName = "节点202" });
Node.Children.Add(new TreeViewEx.TreeViewExNode() { IsExpanded = false, Level = 2, DisplayName = "节点203" });
ModelList.Add(Node);
Node = new TreeViewEx.TreeViewExNode()
{
IsExpanded = true,
Level = 1,
DisplayName = "节点3"
};
ModelList.Add(Node);
this.DataContext = this;
}
public ObservableCollection<TreeViewEx.TreeViewExNode> ModelList { get; set; }
}
}
ModelList采用ObservableCollection、是为了实现动态插入删除节点而设计的。