做项目的时候根据需求,WPF现有的控件不能完全满足我们的需求,
很多时候我们需要对现有的控件做一下加工。
最简单的我们可能会把Tree转换成List形式有的叫Grid形式就像下图一样
今天我先做一个完全用样式加工的例子,有时间我再把它做深加工写成一下通能形式
我们要先把treeView重写一下
public class TreeListView : TreeView
//这两个默认的是TreeViewItem
protected override DependencyObject GetContainerForItemOverride()//创建或标识用于显示指定项的元素。
return new TreeListViewItem();
protected override bool IsItemItsOwnContainerOverride(object item)//确定指定项是否是(或可作为)其自己的 ItemContainer
//return item is TreeListViewItem;
bool _isTreeLVI = item is TreeListViewItem;
return _isTreeLVI;
public class TreeListViewItem : TreeViewItem
/// <summary>
/// hierarchy
/// </summary>
public int Level
if (_level == -1)
TreeListViewItem parent =
ItemsControl.ItemsControlFromItemContainer(this) as TreeListViewItem;//返回拥有指定的容器元素中 ItemsControl 。
_level = (parent != null) ? parent.Level + 1 : 0;
return _level;
protected override DependencyObject GetContainerForItemOverride()
return new TreeListViewItem();
protected override bool IsItemItsOwnContainerOverride(object item)
//return item is TreeListViewItem;
bool _isITV = item is TreeListViewItem;
return _isITV;
private int _level = -1;
上边是对TreeView的重写,因为TreeView是有层级关系的我们做的重写就把它的层级返回来
我们还要有一个列宽的转换
/// <summary>
/// </summary>
public class LevelToIndentConverter : IValueConverter
public object Convert(object o, Type type, object parameter, CultureInfo culture)
return new Thickness((int)o * c_IndentSize, 0, 0, 0);
public object ConvertBack(object o, Type type, object parameter, CultureInfo culture)
throw new NotSupportedException();
private const double c_IndentSize = 25.0;
下边是样式和使用方法
我们是把TreeView的样式加上了GridViewColumnCollection实现 的这个TreeView和ListView一样有标头和列
<Window x:Class="TreeViewListDemoT.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:TreeViewListDemoT"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style x:Key="ExpandCollapseToggleStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Width" Value="19"/>
<Setter Property="Height" Value="13"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Width="19" Height="13" Background="Transparent">
<Border Width="9" Height="9" BorderThickness="1" BorderBrush="#FF7898B5" CornerRadius="1" SnapsToDevicePixels="true">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="White" Offset=".2"/>
<GradientStop Color="#FFC0B7A6" Offset="1"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
<Path x:Name="ExpandPath" Margin="1,1,1,1" Fill="Black"
Data="M 0 2 L 0 3 L 2 3 L 2 5 L 3 5 L 3 3 L 5 3 L 5 2 L 3 2 L 3 0 L 2 0 L 2 2 Z"/>
</Border>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Data" TargetName="ExpandPath" Value="M 0 2 L 0 3 L 5 3 L 5 2 Z"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<l:LevelToIndentConverter x:Key="LevelToIndentConverter"/>
<DataTemplate x:Key="CellTemplate_Name">
<DockPanel>
<ToggleButton x:Name="Expander" Style="{StaticResource ExpandCollapseToggleStyle}" Margin="{Binding Level,
Converter={StaticResource LevelToIndentConverter},RelativeSource={RelativeSource AncestorType={x:Type l:TreeListViewItem}}}"
IsChecked="{Binding Path=IsExpanded,RelativeSource={RelativeSource AncestorType={x:Type l:TreeListViewItem}}}" ClickMode="Press"/>
<TextBlock Text="{Binding Name}"/>
</DockPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=HasItems,RelativeSource={RelativeSource AncestorType={x:Type l:TreeListViewItem}}}" Value="False">
<Setter TargetName="Expander" Property="Visibility" Value="Hidden"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
<GridViewColumnCollection x:Key="gvcc">
<GridViewColumn Header="Name" CellTemplate="{StaticResource CellTemplate_Name}" />
<GridViewColumn Header="Age" DisplayMemberBinding="{Binding Age}" Width="60" />
<GridViewColumn Header="Sex" DisplayMemberBinding="{Binding Sex}" Width="60"/>
</GridViewColumnCollection>
<Style TargetType="{x:Type l:TreeListViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type l:TreeListViewItem}">
<StackPanel>
<Border Name="Bd"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<GridViewRowPresenter x:Name="PART_Header"
Content="{TemplateBinding Header}"
Columns="{StaticResource gvcc}" />
</Border>
<ItemsPresenter x:Name="ItemsHost" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="false">
<Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed"/>
</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="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type l:TreeListView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type l:TreeListView}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<DockPanel>
<GridViewHeaderRowPresenter Columns="{StaticResource gvcc}" DockPanel.Dock="Top"/>
<Border BorderThickness="2">
<ItemsPresenter/>
</Border>
</DockPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<l:TreeListView x:Name="_list" ItemsSource="{Binding Children}" BorderThickness="2">
<l:TreeListView.ItemTemplate >
<HierarchicalDataTemplate ItemsSource="{Binding Children}" >
<Border BorderThickness="2" BorderBrush="Yellow" CornerRadius="0" Margin="1" x:Name="back" MinWidth="70"
DataContext="{Binding}" >
<StackPanel Orientation="Horizontal" Margin="2">
<TextBlock Text="{Binding Text}" Margin="2 0"/>
</StackPanel>
</Border>
</HierarchicalDataTemplate>
</l:TreeListView.ItemTemplate>
</l:TreeListView>
</Grid>
</Window>
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.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 TreeViewListDemoT
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
public MainWindow()
InitializeComponent();
ObjForTest root = new ObjForTest();
ObjForTest depart = new ObjForTest("Department", null, "");
ObjForTest c1 = new ObjForTest( "li", 45, "M");
ObjForTest c2 = new ObjForTest( "xu", 30, "W");
ObjForTest c3 = new ObjForTest("zhang", 22, "M");
ObjForTest cc1 = new ObjForTest( "shen", 30, "M");
ObjForTest cc2 = new ObjForTest( "zhao", 18, "W");
ObjForTest cc3 = new ObjForTest( "wang", 32, "M");
ObjForTest ccc1 = new ObjForTest( "qian", 20, "W");
root.Children.Add(depart);
depart.Children.Add(c1);
depart.Children.Add(c2);
depart.Children.Add(c3);
c1.Children.Add(cc1);
c2.Children.Add(cc2);
c3.Children.Add(cc3);
cc1.Children.Add(ccc1);
this._list.ItemsSource = root.Children;
public class ObjForTest
public ObjForTest() { }
public ObjForTest( string name, int? age, string sex)
this._sex = sex;
this._age = age;
this._name = name;
private string _name;
private int? _age;
private string _sex;
public string Sex
get { return this._sex; }
set { this._sex = value; }
public int? Age
get { return this._age; }
set { this._age = value; }
public string Name
get { return _name; }
_name = value;
private ObservableCollection<ObjForTest> _children = new ObservableCollection<ObjForTest>();
public ObservableCollection<ObjForTest> Children
get { return _children; }
最后给代码下载 TreeViewListDemoT.rar