• 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>类型

     显示效果:

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

  • 相关阅读:
    ubuntu一些记录
    unittest添加测试用例方法
    弹出框处理
    无法连接终端
    Python 断言
    Appium_Python_Api文档
    pycharm快捷键
    appium运行时启动失败
    appium运行时每次默认弹出appiumsetting与unlock重装,关闭这两个步骤的方法
    SpringBoot的jar包引用外部properties文件
  • 原文地址:https://www.cnblogs.com/280850911/p/3805221.html
Copyright © 2020-2023  润新知