做项目的时候根据需求,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 { get { 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> <Grid> <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; } set { _name = value; } } private ObservableCollection<ObjForTest> _children = new ObservableCollection<ObjForTest>(); public ObservableCollection<ObjForTest> Children { get { return _children; } } } }
最后给代码下载 TreeViewListDemoT.rar