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="{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="true">

                                    <Setter TargetName="staTree" Property="Background" Value="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 = value;

                tvZsmTree.ItemsSource = _itemsSourceData;

            }

        }



        /// <summary>

        /// 设置对应Id的项为选中状态

        /// </summary>

        /// <param name="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 = treeList;//treeList为IList<TreeModel>类型

 显示效果:WPF 带CheckBox、图标的TreeView

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

你可能感兴趣的:(checkbox)