首页 > 代码库 > WPF 带CheckBox、图标的TreeView

WPF 带CheckBox、图标的TreeView

WPF 带CheckBox、图标的TreeView

在WPF实际项目开发的时候,经常会用到带CheckBox的TreeView,虽然微软在WPF的TreeView中没有提供该功能,但是微软在WPF中提供强大的ItemTemplate模板功能和自定义样式,那我们可以自己写一个这样的控件供自己使用。

 我自己写的这个比较简单。

首先写一个供TreeView使用的数据模型,并且实现INotifyPropertyChanged接口,用于向客户端(通常是执行绑定的客户端)发出某一属性值已更改的通知,当属性改变时,相应的UI表现也改变。主要字段Id,Name,Icon,ToolTip,IsChecked,IsExpanded,Parent,Children

//***************************************************//// 文件名(FileName)  : TreeModel.cs//// 作者(Author)      : zsm//// 创建时间(CreateAt):  2013-03-18 14:23:58//// 描述(Description) : 供TreeView实用的数据模型////***************************************************using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ComponentModel;namespace Com.FMS.Model{    public class TreeModel : INotifyPropertyChanged    {        #region 私有变量        /// <summary>        /// Id值        /// </summary>        private string _id;        /// <summary>        /// 显示的名称        /// </summary>        private string _name;        /// <summary>        /// 图标路径        /// </summary>        private string _icon;        /// <summary>        /// 选中状态        /// </summary>        private bool _isChecked;        /// <summary>        /// 折叠状态        /// </summary>        private bool _isExpanded;        /// <summary>        /// 子项        /// </summary>        private IList<TreeModel> _children;        /// <summary>        /// 父项        /// </summary>        private TreeModel _parent;        #endregion         /// <summary>        /// 构造        /// </summary>        public TreeModel()        {            Children = new List<TreeModel>();            _isChecked = false;            IsExpanded = false;            _icon = "/Images/16_16/folder_go.png";        }        /// <summary>        /// 键值        /// </summary>        public string Id        {            get { return _id; }            set { _id = value; }        }        /// <summary>        /// 显示的字符        /// </summary>        public string Name        {            get { return _name; }            set { _name = value; }        }        /// <summary>        /// 图标        /// </summary>        public string Icon        {            get { return _icon; }            set { _icon = value; }        }        /// <summary>        /// 指针悬停时的显示说明        /// </summary>        public string ToolTip         {            get             {                return String.Format("{0}-{1}", Id, Name);            }        }        /// <summary>        /// 是否选中        /// </summary>        public bool IsChecked        {            get            {                return _isChecked;            }            set            {                if (value != _isChecked)                {                    _isChecked = value;                    NotifyPropertyChanged("IsChecked");                    if (_isChecked)                    {                        //如果选中则父项也应该选中                        if (Parent != null)                        {                            Parent.IsChecked = true;                        }                    }                    else                    {                        //如果取消选中子项也应该取消选中                        foreach (TreeModel child in Children)                        {                            child.IsChecked = false;                        }                    }                }            }        }        /// <summary>        /// 是否展开        /// </summary>        public bool IsExpanded        {            get { return _isExpanded; }            set            {                if (value != _isExpanded)                {                    //折叠状态改变                    _isExpanded = value;                    NotifyPropertyChanged("IsExpanded");                }            }        }        /// <summary>        /// 父项        /// </summary>        public TreeModel Parent        {            get { return _parent; }            set { _parent = value; }        }        /// <summary>        /// 子项        /// </summary>        public IList<TreeModel> Children        {            get { return _children; }            set { _children = value; }        }        /// <summary>        /// 设置所有子项的选中状态        /// </summary>        /// <param name="isChecked"></param>        public void SetChildrenChecked(bool isChecked)        {            foreach (TreeModel child in Children)            {                child.IsChecked = IsChecked;                child.SetChildrenChecked(IsChecked);            }        }        /// <summary>        /// 设置所有子项展开状态        /// </summary>        /// <param name="isExpanded"></param>        public void SetChildrenExpanded(bool isExpanded)         {            foreach (TreeModel child in Children)            {                child.IsExpanded = isExpanded;                child.SetChildrenExpanded(isExpanded);            }        }        /// <summary>        /// 属性改变事件        /// </summary>        public event PropertyChangedEventHandler PropertyChanged;        private void NotifyPropertyChanged(String info)        {            if (PropertyChanged != null)            {                PropertyChanged(this, new PropertyChangedEventArgs(info));            }        }    }}

创建一个用户控件,主要含有一个TreeView控件,ContextMenu右键菜单项,UI代码如下(其中的路径请根据实际修改):

<UserControl x:Class="Com.FMS.View.UserControls.ZsmTreeView"             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"              xmlns:local="clr-namespace:Com.FMS.Model"             mc:Ignorable="d"              d:DesignHeight="300" d:DesignWidth="300">    <Grid>        <DockPanel>            <Border DockPanel.Dock="Bottom">                <StackPanel Orientation="Horizontal" ToolTip="右键有更多功能哦!">                    <Image Height="16" Width="16" Source="Images/16_16/emoticon_smile.png"></Image>                    <Label Content="右键有更多功能哦!" Foreground="Gray"></Label>                </StackPanel>            </Border>            <Border>                <TreeView Name="tvZsmTree">                    <TreeView.ContextMenu>                        <ContextMenu>                            <MenuItem Name="menuExpandAll" Header="全部展开" Click="menuExpandAll_Click">                                <MenuItem.Icon>                                    <Image Source="/Com.FMS;component/Images/16_16/folder_open_arrow.png" />                                </MenuItem.Icon>                            </MenuItem>                            <MenuItem Name="menuUnExpandAll" Header="全部折叠" Click="menuUnExpandAll_Click">                                <MenuItem.Icon>                                    <Image Source="/Com.FMS;component/Images/16_16/folder_close_arrow.png" />                                </MenuItem.Icon>                            </MenuItem>                            <MenuItem Name="menuSelectAll" Header="全部选中" Click="menuSelectAll_Click">                                <MenuItem.Icon>                                    <Image Source="/Com.FMS;component/Images/16_16/tick.png" />                                </MenuItem.Icon>                            </MenuItem>                            <MenuItem Name="menuUnSelectAll" Header="全部取消" Click="menuUnSelectAll_Click">                                <MenuItem.Icon>                                    <Image Source="/Com.FMS;component/Images/16_16/delete.png" />                                </MenuItem.Icon>                            </MenuItem>                        </ContextMenu>                    </TreeView.ContextMenu>                    <TreeView.ItemContainerStyle>                        <Style TargetType="TreeViewItem">                            <Setter Property="IsExpanded" Value="http://www.mamicode.com/{Binding IsExpanded, Mode=TwoWay}"></Setter>                            <EventSetter Event="TreeViewItem.PreviewMouseRightButtonDown" Handler="TreeViewItem_PreviewMouseRightButtonDown"/>                        </Style>                    </TreeView.ItemContainerStyle>                    <TreeView.ItemTemplate>                        <HierarchicalDataTemplate DataType="{x:Type local:TreeModel}"  ItemsSource="{Binding Children}">                            <StackPanel  Margin="-2,0,0,0" Orientation="Horizontal" x:Name="staTree">                                <CheckBox ToolTip="{Binding ToolTip}" FontSize="14" FontFamily="微软雅黑" Tag="{Binding Children}" IsChecked="{Binding IsChecked, Mode=TwoWay}">                                    <StackPanel Orientation="Horizontal">                                        <Image VerticalAlignment="Center" Source="{Binding Icon}" ></Image>                                        <TextBlock Text="{Binding Name}"></TextBlock>                                    </StackPanel>                                    <CheckBox.ContextMenu>                                        <ContextMenu>                                            <MenuItem Name="menuSelectAllChild" Header="全部选中子项" Click="menuSelectAllChild_Click">                                                <MenuItem.Icon>                                                    <Image Source="/Com.FMS;component/Images/16_16/tick.png" />                                                </MenuItem.Icon>                                            </MenuItem>                                        </ContextMenu>                                    </CheckBox.ContextMenu>                                </CheckBox>                            </StackPanel>                            <HierarchicalDataTemplate.Triggers>                                <DataTrigger Binding="{Binding IsChecked}" Value="http://www.mamicode.com/true">                                    <Setter TargetName="staTree" Property="Background" Value="http://www.mamicode.com/White"/>                                </DataTrigger>                            </HierarchicalDataTemplate.Triggers>                        </HierarchicalDataTemplate>                    </TreeView.ItemTemplate>                </TreeView>            </Border>        </DockPanel>    </Grid></UserControl>

交互逻辑的代码中,现在主要有控件数据ItemsSourceData属性,设置对应Id的项为选中状态SetCheckedById、忽略层次关系的情况下获取选中项CheckedItemsIgnoreRelation等方法,以及右键的选中所有子项菜单、全部选中、全部取消选中、全部折叠、全部展开等事件,交互逻辑代码为:

//***************************************************//// 文件名(FileName)  : ZsmTreeView.xaml.cs//// 作者(Author)      : zsm//// 创建时间(CreateAt):  2013-03-15 16:52:40//// 描述(Description) : 带CheckBox的TreeView控件的交互逻辑代码////***************************************************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;namespace Com.FMS.View.UserControls{    /// <summary>    /// ZsmTreeView.xaml 的交互逻辑    /// </summary>    public partial class ZsmTreeView : UserControl    {        #region 私有变量属性        /// <summary>        /// 控件数据        /// </summary>        private IList<Model.TreeModel> _itemsSourceData;        #endregion        /// <summary>        /// 构造        /// </summary>        public ZsmTreeView()        {            InitializeComponent();        }        /// <summary>        /// 控件数据        /// </summary>        public IList<Model.TreeModel> ItemsSourceData         {            get { return _itemsSourceData; }            set            {                _itemsSourceData = http://www.mamicode.com/value;"id"></param>        /// <returns></returns>        public int SetCheckedById(string id, IList<Model.TreeModel> treeList)         {            foreach (var tree in treeList)            {                if (tree.Id.Equals(id))                {                    tree.IsChecked = true;                    return 1;                }                if (SetCheckedById(id, tree.Children) == 1)                {                    return 1;                }            }            return 0;        }        /// <summary>        /// 设置对应Id的项为选中状态        /// </summary>        /// <param name="id"></param>        /// <returns></returns>        public int SetCheckedById(string id)        {            foreach (var tree in ItemsSourceData)            {                if (tree.Id.Equals(id))                {                    tree.IsChecked = true;                    return 1;                }                if (SetCheckedById(id, tree.Children) == 1)                {                    return 1;                }            }            return 0;        }        /// <summary>        /// 获取选中项        /// </summary>        /// <returns></returns>        public IList<Model.TreeModel> CheckedItemsIgnoreRelation()        {            return GetCheckedItemsIgnoreRelation(_itemsSourceData);        }        /// <summary>        /// 私有方法,忽略层次关系的情况下,获取选中项        /// </summary>        /// <param name="list"></param>        /// <returns></returns>        private IList<Model.TreeModel> GetCheckedItemsIgnoreRelation(IList<Model.TreeModel> list)        {            IList<Model.TreeModel> treeList = new List<Model.TreeModel>();            foreach (var tree in list)            {                if (tree.IsChecked)                {                    treeList.Add(tree);                }                foreach (var child in GetCheckedItemsIgnoreRelation(tree.Children))                {                    treeList.Add(child);                }            }            return treeList;        }        /// <summary>        /// 选中所有子项菜单事件        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void menuSelectAllChild_Click(object sender, RoutedEventArgs e)        {            if (tvZsmTree.SelectedItem != null)            {                Model.TreeModel tree = (Model.TreeModel)tvZsmTree.SelectedItem;                tree.IsChecked = true;                tree.SetChildrenChecked(true);            }        }        /// <summary>        /// 全部展开菜单事件        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void menuExpandAll_Click(object sender, RoutedEventArgs e)        {            foreach (Model.TreeModel tree in tvZsmTree.ItemsSource)            {                tree.IsExpanded = true;                tree.SetChildrenExpanded(true);            }        }        /// <summary>        /// 全部折叠菜单事件        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void menuUnExpandAll_Click(object sender, RoutedEventArgs e)        {            foreach (Model.TreeModel tree in tvZsmTree.ItemsSource)            {                tree.IsExpanded = false;                tree.SetChildrenExpanded(false);            }        }        /// <summary>        /// 全部选中事件        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void menuSelectAll_Click(object sender, RoutedEventArgs e)        {            foreach (Model.TreeModel tree in tvZsmTree.ItemsSource)            {                tree.IsChecked = true;                tree.SetChildrenChecked(true);            }        }        /// <summary>        /// 全部取消选中        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void menuUnSelectAll_Click(object sender, RoutedEventArgs e)        {            foreach (Model.TreeModel tree in tvZsmTree.ItemsSource)            {                tree.IsChecked = false;                tree.SetChildrenChecked(false);            }        }        /// <summary>        /// 鼠标右键事件        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void TreeViewItem_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)        {            TreeViewItem item = VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem;            if (item != null)            {                item.Focus();                e.Handled = true;            }        }        static DependencyObject VisualUpwardSearch<T>(DependencyObject source)        {            while (source != null && source.GetType() != typeof(T))                source = VisualTreeHelper.GetParent(source);            return source;        }    }}

在使用控件的时候,要在xaml中引入命名控件(根据实际引入)  

xmlns:my="clr-namespace:Com.FMS.View.UserControls"
<!--使用控件-->
<my:ZsmTreeView x:Name="ztvModule" /> 
为控件赋值:
ztvModule.ItemsSourceData = http://www.mamicode.com/treeList;//treeList为IList类型

 显示效果:

其实还可以完成共多功能,等有时间在去写。