zoukankan      html  css  js  c++  java
  • 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="{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>类型

     显示效果:

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

  • 相关阅读:
    〖Linux〗Kubuntu设置打开应用时就只在打开时的工作区显示
    〖Linux〗Kubuntu, the application 'Google Chrome' has requested to open the wallet 'kdewallet'解决方法
    unity, dll is not allowed to be included or could not be found
    android check box 自定义图片
    unity, ios skin crash
    unity, Collider2D.bounds的一个坑
    unity, ContentSizeFitter立即生效
    类里的通用成员函数应声明为static
    unity, Gizmos.DrawMesh一个坑
    直线切割凹多边形
  • 原文地址:https://www.cnblogs.com/280850911/p/3805221.html
Copyright © 2011-2022 走看看