WPF TreeGrid(树形展开的表格)

来源:互联网 发布:手机拼音打字软件 编辑:程序博客网 时间:2024/04/27 14:21

一直都想要个树形展开的表格 像这样的



今天心血来潮就简单做了个TreeGrid 喜欢的同学可以下载下去自己研究下,其实也比较简单主要就是TreeView TreeViewItem再配合GridViewHeaderRowPresenter、GridViewRowPresenter、GridViewColumnCollection定制style基本上就可以实现以上效果

本文中涉及大量模板,绑定等知识,如果刚刚入门还没有了解以上知识的同学可以先补下课,然后再来看,以免浪费时间。

闲话不多说,直接上代码:

前台代码 MainWindow.xaml

<Window x:Class="TreeGrid.MainWindow"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        xmlns:local="clr-namespace:TreeGrid"        Title="MainWindow" Height="350" Width="525">    <Window.Resources>        <local:LevelToMarginConverter x:Key="LevelToIndentConverter"/>                <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>        <DataTemplate x:Key="CellTemplate_Name">            <DockPanel>                <ToggleButton x:Name="Expander"                       Style="{StaticResource ExpandCollapseToggleStyle}"                       Margin="{Binding Level,Converter={StaticResource LevelToIndentConverter}}"                      IsChecked="{Binding Path=IsExpanded,                                 RelativeSource={RelativeSource                                                  AncestorType=                                                  {x:Type TreeViewItem}}}"                      ClickMode="Press"/>                <TextBlock Text="{Binding Name}"/>            </DockPanel>            <DataTemplate.Triggers>                <DataTrigger Binding="{Binding Path=HasItems,                               RelativeSource={RelativeSource                                AncestorType={x:Type TreeViewItem}}}"                      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="JobTitle"                       DisplayMemberBinding="{Binding JobTitle}" Width="60"/>            <GridViewColumn Header="Age"                       DisplayMemberBinding="{Binding Age}" Width="60" />            <GridViewColumn Header="Sex"                       DisplayMemberBinding="{Binding Sex}" Width="60"/>                    </GridViewColumnCollection>                <Style TargetType="{x:Type TreeViewItem}">            <Setter Property="Template">                <Setter.Value>                    <ControlTemplate TargetType="{x:Type TreeViewItem}">                        <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 TreeView}">            <Setter Property="Template">                <Setter.Value>                    <ControlTemplate TargetType="{x:Type TreeView}">                        <Border BorderBrush="{TemplateBinding BorderBrush}"                    BorderThickness="{TemplateBinding BorderThickness}">                            <DockPanel>                                <GridViewHeaderRowPresenter Columns="{StaticResource gvcc}"                                            DockPanel.Dock="Top"/>                                <ItemsPresenter/>                            </DockPanel>                        </Border>                    </ControlTemplate>                </Setter.Value>            </Setter>        </Style>    </Window.Resources>    <Grid>        <TreeView Name="_list" Margin="0" BorderThickness="0" VerticalAlignment="Stretch" Background="Transparent" ItemsSource="{Binding Children}" >            <TreeView.ItemTemplate>                <HierarchicalDataTemplate ItemsSource="{Binding Children}">                    <Border CornerRadius="0" Margin="1"  x:Name="back" MinWidth="70"                                Background="Transparent" DataContext="{Binding}" >                        <StackPanel Orientation="Horizontal" Margin="2">                            <TextBlock Text="{Binding Text}" Margin="2 0"/>                        </StackPanel>                    </Border>                </HierarchicalDataTemplate>            </TreeView.ItemTemplate>        </TreeView>    </Grid></Window>


Window.Resources里面是所用到的style和资源,其实整个窗口里面就只有一个TreeView在codebehind绑定一个对象的Children属性。这里的treeview对象的绑定涉及到HierarchicalDataTemplate它是一个递归的数据模板。而在resources里面值得注意的是几个地方

1. <local:LevelToMarginConverter x:Key="LevelToIndentConverter"/> 这句是在定义一个Converter资源,因为我是使用绑定对象的level值来绑定前台的缩进大小,但是level属性是int型的 要转换为margin的thickness类型,所以我会用到一个继承自IValueConverter的 LevelToMarginConverter 的类

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Globalization;using System.Windows;using System.Windows.Data;namespace TreeGrid{    public class LevelToMarginConverter : 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 = 15.0;    }}

2.TreeViewItem的style中GridViewRowPresenter是用来显示自身的值,itemspresernter是用来显示树形下级内容的
<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>

3.TreeView的style中 GridViewHeaderRowPresenter用来显示表头,ItemsPresenter用来显示TreeViewITem的列表
<ControlTemplate TargetType="{x:Type TreeView}">                        <Border BorderBrush="{TemplateBinding BorderBrush}"                    BorderThickness="{TemplateBinding BorderThickness}">                            <DockPanel>                                <GridViewHeaderRowPresenter Columns="{StaticResource gvcc}"                                            DockPanel.Dock="Top"/>                                <ItemsPresenter/>                            </DockPanel>                        </Border>                    </ControlTemplate>


codebehind代码如下

using System;using System.Collections.Generic;using System.Linq;using System.Text;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;using System.ComponentModel;using System.Collections.ObjectModel;namespace TreeGrid{    /// <summary>    /// Interaction logic for MainWindow.xaml    /// </summary>    public partial class MainWindow : Window    {        public MainWindow()        {            InitializeComponent();            ObjForTest root = new ObjForTest("root", "root",0,"",0);            ObjForTest c1 = new ObjForTest("CEO", "Leo",45,"M",1);            ObjForTest c2 = new ObjForTest("CFO", "Tami",46,"FM",1);            ObjForTest c3 = new ObjForTest("COO", "Jack",47,"M",1);            ObjForTest cc1 = new ObjForTest("Manager", "John", 30, "M", 2);            ObjForTest cc2 = new ObjForTest("Manager", "Lee", 31, "FM", 2);            ObjForTest cc3 = new ObjForTest("Manager", "Chris", 32, "M", 2);            ObjForTest ccc1 = new ObjForTest("Worker", "Evan", 25,"FM",3);            root.Children.Add(c1);            root.Children.Add(c2);            root.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 : INotifyPropertyChanged    {        public ObjForTest(string title, string name,int age,string sex,int level)        {            this._jobTitle = title;            this._sex = sex;            this._age = age;            this._name = name;            this._level = level;        }        private string _name;        private int _age;        private string _sex;        private int _level;        private string _jobTitle;        public string Sex { get { return this._sex; } set { this._sex = value; } }        public int Age { get { return this._age; } set { this._age = value; } }        public int Level        {            get             {                 return this._level;            }            set            {                _level = value;                if (PropertyChanged != null)                    PropertyChanged(this, new PropertyChangedEventArgs("Level"));            }        }        public string JobTitle        {            get { return _jobTitle; }            set            {                _jobTitle = value;                if (PropertyChanged != null)                    PropertyChanged(this, new PropertyChangedEventArgs("JobTitle"));            }        }        public string Name        {            get { return _name; }            set            {                _name = value;                if (PropertyChanged != null)                    PropertyChanged(this, new PropertyChangedEventArgs("Name"));            }        }        private ObservableCollection<ObjForTest> _children = new ObservableCollection<ObjForTest>();        public ObservableCollection<ObjForTest> Children        {            get { return _children; }        }        public event PropertyChangedEventHandler PropertyChanged;    }}

ObjForTest是用来绑定的对象this._list.ItemsSource = root.Children;这句是用来绑定对象的children对象

完整实例可以  点击此处下载   如果有更好的方法也可以给我留言 谢谢!

原创粉丝点击