WPF 自定义TreeView控件 绑定子列表

<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、是为了实现动态插入删除节点而设计的。


MyControls 代码分享仅控件代码调用请看本文章


  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值