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

显示效果:

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

WPF 带CheckBox、图标的TreeView

时间: 2024-08-03 23:58:59

WPF 带CheckBox、图标的TreeView的相关文章

c# WPF——创建带有图标的TreeView

1.使用数据模板对TreeViewItem进行更改 2.xaml中重写TreeviewItem的控件模板 3.继承TreeViewItem(TreeView中的元素),后台进行控件重写.(介绍此方法) 代码: ImageSource iconSource;//图标对象 TextBlock textBlock; Image icon;//treeviewitem中的图标 public TreeViewWithIcons() { StackPanel stack = new StackPanel()

wpf企业应用之带选项框的TreeView

wpf里面实现层次绑定主要使用HierarchicalDataTemplate,这里主要谈一谈带checkbox的treeview,具体效果见 wpf企业级开发中的几种常见业务场景. 先来看一下我的控件绑定,我这里实现的是模块权限的编辑.具体效果就是选中一个节点,后代节点.祖代节点状态都会发生相应变化,具体变化逻辑大家都懂的,描述起来很罗嗦. <TreeView Name="TreeView_Right" ItemsSource="{Binding ModuleRigh

[Android 成长之路]2-实现带图标的ListView

--by San[[email protected]] 在编写列表时,如果是普通的列表,使用ListView + ArrayAdapter 即可实现,但是如果要在每个列表项中文字前配一个图标了,或者在文字后面再配一个图标,这个就可以用 SimpleAdapter 实现了,不要被它的名字欺骗了,It is not simple, it is powerful. 我们以制作一个带图标的菜单列表为例,首先我们创建一个布局文件 menu_frame.xml,里面包含一个 ListView, 代码如下:

Silverlight TreeView 带 checkbox和图片

前段时间做Silverlight TreeView 控件,但是要带checkbox和图片,在网上到处找相关的例子,效果图如下 xaml代码 <UserControl x:Class="SlmenuTest.Tree" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xam

Java数据结构——带权图

带权图的最小生成树——Prim算法和Kruskal算法 带权图的最短路径算法——Dijkstra算法 package graph; // path.java // demonstrates shortest path with weighted, directed graphs 带权图的最短路径算法 // to run this program: C>java PathApp ////////////////////////////////////////////////////////////

【转】带checkbox的ListView实现(二)——自定义Checkable控件的实现方法

原文网址:http://blog.csdn.net/harvic880925/article/details/40475367 前言:前一篇文章给大家展示了传统的Listview的写法,但有的时候我们并不想在DataHolder类中加一个标识是否选中的checked的成员变量,因为在项目开发中,大部分的ListItemLayout布局都是大家共用的,有些人根本不需要checkbox控件,所以会在初始化的时候把这个控件给隐藏掉,但我们的DataHolder在构造的时候以及ListItemAdapt

用无向带权图实现校园导航系统

学校数据结构的课程实验之一. 用到的数据结构:无向带权图 用到的算法:Floyd最短路径算法,深度优先搜索(递归实现) 需求分析: 设计一个校园导航程序,为访客提供各种信息查询服务: 1. 以图中各顶点表示校内各单位地点,存放单位名称,代号,简介等信息:以边表示路径,存放路径长度等相关信息. 2. 图中任意单位地点相关信息的查询. 3. 图中任意单位的问路查询,即查询任意两个单位之间的一条最短的路径. 2. 从图中任意单位地点出发的一条深度优先遍历路径. 主函数: 1 #include <ios

邻接矩阵表示有向带权图

#include <stdio.h> #include <stdlib.h> #include <string.h> typedef char VertexType[5]; //存储顶点值 #define MaxSize 50 #define INIT 10000 typedef struct //邻接矩阵,存储弧的信息 {     int adj; }ArcNode,AdjMatrix[MaxSize][MaxSize]; typedef struct   //图的类

带权图的最短路径算法(Dijkstra)实现

一,介绍 本文实现带权图的最短路径算法.给定图中一个顶点,求解该顶点到图中所有其他顶点的最短路径 以及 最短路径的长度.在决定写这篇文章之前,在网上找了很多关于Dijkstra算法实现,但大部分是不带权的.不带权的Dijkstra算法要简单得多(可参考我的另一篇:无向图的最短路径算法JAVA实现):而对于带权的Dijkstra算法,最关键的是如何“更新邻接点的权值”.本文采用最小堆主辅助,以重新构造堆的方式实现更新邻接点权值. 对于图而言,存在有向图和无向图.本算法只需要修改一行代码,即可同时实