做项目的时候根据需求,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