WPF 带CheckBox、图标的TreeView

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

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

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

  1. //***************************************************
  2. //
  3. // 文件名(FileName) : TreeModel.cs
  4. //
  5. // 作者(Author) : zsm
  6. //
  7. // 创建时间(CreateAt): 2013-03-18 14:23:58
  8. //
  9. // 描述(Description) : 供TreeView实用的数据模型
  10. //
  11. //***************************************************
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Linq;
  15. using System.Text;
  16. using System.ComponentModel;
  17.  
  18. namespace Com.FMS.Model
  19. {
  20. public class TreeModel : INotifyPropertyChanged
  21. {
  22. #region 私有变量
  23. /// <summary>
  24. /// Id值
  25. /// </summary>
  26. private string _id;
  27. /// <summary>
  28. /// 显示的名称
  29. /// </summary>
  30. private string _name;
  31. /// <summary>
  32. /// 图标路径
  33. /// </summary>
  34. private string _icon;
  35. /// <summary>
  36. /// 选中状态
  37. /// </summary>
  38. private bool _isChecked;
  39. /// <summary>
  40. /// 折叠状态
  41. /// </summary>
  42. private bool _isExpanded;
  43. /// <summary>
  44. /// 子项
  45. /// </summary>
  46. private IList<TreeModel> _children;
  47. /// <summary>
  48. /// 父项
  49. /// </summary>
  50. private TreeModel _parent;
  51. #endregion
  52.  
  53. /// <summary>
  54. /// 构造
  55. /// </summary>
  56. public TreeModel()
  57. {
  58. Children = new List<TreeModel>();
  59. _isChecked = false;
  60. IsExpanded = false;
  61. _icon = "/Images/16_16/folder_go.png";
  62. }
  63.  
  64. /// <summary>
  65. /// 键值
  66. /// </summary>
  67. public string Id
  68. {
  69. get { return _id; }
  70. set { _id = value; }
  71. }
  72.  
  73. /// <summary>
  74. /// 显示的字符
  75. /// </summary>
  76. public string Name
  77. {
  78. get { return _name; }
  79. set { _name = value; }
  80. }
  81.  
  82. /// <summary>
  83. /// 图标
  84. /// </summary>
  85. public string Icon
  86. {
  87. get { return _icon; }
  88. set { _icon = value; }
  89. }
  90.  
  91. /// <summary>
  92. /// 指针悬停时的显示说明
  93. /// </summary>
  94. public string ToolTip
  95. {
  96. get
  97. {
  98. return String.Format("{0}-{1}", Id, Name);
  99. }
  100. }
  101.  
  102. /// <summary>
  103. /// 是否选中
  104. /// </summary>
  105. public bool IsChecked
  106. {
  107. get
  108. {
  109. return _isChecked;
  110. }
  111. set
  112. {
  113. if (value != _isChecked)
  114. {
  115. _isChecked = value;
  116. NotifyPropertyChanged("IsChecked");
  117.  
  118. if (_isChecked)
  119. {
  120. //如果选中则父项也应该选中
  121. if (Parent != null)
  122. {
  123. Parent.IsChecked = true;
  124. }
  125. }
  126. else
  127. {
  128. //如果取消选中子项也应该取消选中
  129. foreach (TreeModel child in Children)
  130. {
  131. child.IsChecked = false;
  132. }
  133. }
  134. }
  135. }
  136. }
  137.  
  138. /// <summary>
  139. /// 是否展开
  140. /// </summary>
  141. public bool IsExpanded
  142. {
  143. get { return _isExpanded; }
  144. set
  145. {
  146. if (value != _isExpanded)
  147. {
  148. //折叠状态改变
  149. _isExpanded = value;
  150. NotifyPropertyChanged("IsExpanded");
  151. }
  152. }
  153. }
  154.  
  155. /// <summary>
  156. /// 父项
  157. /// </summary>
  158. public TreeModel Parent
  159. {
  160. get { return _parent; }
  161. set { _parent = value; }
  162. }
  163.  
  164. /// <summary>
  165. /// 子项
  166. /// </summary>
  167. public IList<TreeModel> Children
  168. {
  169. get { return _children; }
  170. set { _children = value; }
  171. }
  172.  
  173. /// <summary>
  174. /// 设置所有子项的选中状态
  175. /// </summary>
  176. /// <param name="isChecked"></param>
  177. public void SetChildrenChecked(bool isChecked)
  178. {
  179. foreach (TreeModel child in Children)
  180. {
  181. child.IsChecked = IsChecked;
  182. child.SetChildrenChecked(IsChecked);
  183. }
  184. }
  185.  
  186. /// <summary>
  187. /// 设置所有子项展开状态
  188. /// </summary>
  189. /// <param name="isExpanded"></param>
  190. public void SetChildrenExpanded(bool isExpanded)
  191. {
  192. foreach (TreeModel child in Children)
  193. {
  194. child.IsExpanded = isExpanded;
  195. child.SetChildrenExpanded(isExpanded);
  196. }
  197. }
  198.  
  199. /// <summary>
  200. /// 属性改变事件
  201. /// </summary>
  202. public event PropertyChangedEventHandler PropertyChanged;
  203. private void NotifyPropertyChanged(String info)
  204. {
  205. if (PropertyChanged != null)
  206. {
  207. PropertyChanged(this, new PropertyChangedEventArgs(info));
  208. }
  209. }
  210. }
  211. }

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

  1. <UserControl x:Class="Com.FMS.View.UserControls.ZsmTreeView"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  5. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  6. xmlns:local="clr-namespace:Com.FMS.Model"
  7. mc:Ignorable="d"
  8. d:DesignHeight="300" d:DesignWidth="300">
  9. <Grid>
  10. <DockPanel>
  11. <Border DockPanel.Dock="Bottom">
  12. <StackPanel Orientation="Horizontal" ToolTip="右键有更多功能哦!">
  13. <Image Height="16" Width="16" Source="Images/16_16/emoticon_smile.png"></Image>
  14. <Label Content="右键有更多功能哦!" Foreground="Gray"></Label>
  15. </StackPanel>
  16. </Border>
  17. <Border>
  18. <TreeView Name="tvZsmTree">
  19. <TreeView.ContextMenu>
  20. <ContextMenu>
  21. <MenuItem Name="menuExpandAll" Header="全部展开" Click="menuExpandAll_Click">
  22. <MenuItem.Icon>
  23. <Image Source="/Com.FMS;component/Images/16_16/folder_open_arrow.png" />
  24. </MenuItem.Icon>
  25. </MenuItem>
  26. <MenuItem Name="menuUnExpandAll" Header="全部折叠" Click="menuUnExpandAll_Click">
  27. <MenuItem.Icon>
  28. <Image Source="/Com.FMS;component/Images/16_16/folder_close_arrow.png" />
  29. </MenuItem.Icon>
  30. </MenuItem>
  31. <MenuItem Name="menuSelectAll" Header="全部选中" Click="menuSelectAll_Click">
  32. <MenuItem.Icon>
  33. <Image Source="/Com.FMS;component/Images/16_16/tick.png" />
  34. </MenuItem.Icon>
  35. </MenuItem>
  36. <MenuItem Name="menuUnSelectAll" Header="全部取消" Click="menuUnSelectAll_Click">
  37. <MenuItem.Icon>
  38. <Image Source="/Com.FMS;component/Images/16_16/delete.png" />
  39. </MenuItem.Icon>
  40. </MenuItem>
  41. </ContextMenu>
  42. </TreeView.ContextMenu>
  43. <TreeView.ItemContainerStyle>
  44. <Style TargetType="TreeViewItem">
  45. <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"></Setter>
  46. <EventSetter Event="TreeViewItem.PreviewMouseRightButtonDown" Handler="TreeViewItem_PreviewMouseRightButtonDown"/>
  47. </Style>
  48. </TreeView.ItemContainerStyle>
  49. <TreeView.ItemTemplate>
  50. <HierarchicalDataTemplate DataType="{x:Type local:TreeModel}" ItemsSource="{Binding Children}">
  51. <StackPanel Margin="-2,0,0,0" Orientation="Horizontal" x:Name="staTree">
  52. <CheckBox ToolTip="{Binding ToolTip}" FontSize="14" FontFamily="微软雅黑" Tag="{Binding Children}" IsChecked="{Binding IsChecked, Mode=TwoWay}">
  53. <StackPanel Orientation="Horizontal">
  54. <Image VerticalAlignment="Center" Source="{Binding Icon}" ></Image>
  55. <TextBlock Text="{Binding Name}"></TextBlock>
  56. </StackPanel>
  57. <CheckBox.ContextMenu>
  58. <ContextMenu>
  59. <MenuItem Name="menuSelectAllChild" Header="全部选中子项" Click="menuSelectAllChild_Click">
  60. <MenuItem.Icon>
  61. <Image Source="/Com.FMS;component/Images/16_16/tick.png" />
  62. </MenuItem.Icon>
  63. </MenuItem>
  64. </ContextMenu>
  65. </CheckBox.ContextMenu>
  66. </CheckBox>
  67. </StackPanel>
  68. <HierarchicalDataTemplate.Triggers>
  69. <DataTrigger Binding="{Binding IsChecked}" Value="true">
  70. <Setter TargetName="staTree" Property="Background" Value="White"/>
  71. </DataTrigger>
  72. </HierarchicalDataTemplate.Triggers>
  73. </HierarchicalDataTemplate>
  74. </TreeView.ItemTemplate>
  75. </TreeView>
  76. </Border>
  77. </DockPanel>
  78. </Grid>
  79. </UserControl>

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

  1. //***************************************************
  2. //
  3. // 文件名(FileName) : ZsmTreeView.xaml.cs
  4. //
  5. // 作者(Author) : zsm
  6. //
  7. // 创建时间(CreateAt): 2013-03-15 16:52:40
  8. //
  9. // 描述(Description) : 带CheckBox的TreeView控件的交互逻辑代码
  10. //
  11. //***************************************************
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Linq;
  15. using System.Text;
  16. using System.Windows;
  17. using System.Windows.Controls;
  18. using System.Windows.Data;
  19. using System.Windows.Documents;
  20. using System.Windows.Input;
  21. using System.Windows.Media;
  22. using System.Windows.Media.Imaging;
  23. using System.Windows.Navigation;
  24. using System.Windows.Shapes;
  25.  
  26. namespace Com.FMS.View.UserControls
  27. {
  28. /// <summary>
  29. /// ZsmTreeView.xaml 的交互逻辑
  30. /// </summary>
  31. public partial class ZsmTreeView : UserControl
  32. {
  33. #region 私有变量属性
  34. /// <summary>
  35. /// 控件数据
  36. /// </summary>
  37. private IList<Model.TreeModel> _itemsSourceData;
  38. #endregion
  39.  
  40. /// <summary>
  41. /// 构造
  42. /// </summary>
  43. public ZsmTreeView()
  44. {
  45. InitializeComponent();
  46. }
  47.  
  48. /// <summary>
  49. /// 控件数据
  50. /// </summary>
  51. public IList<Model.TreeModel> ItemsSourceData
  52. {
  53. get { return _itemsSourceData; }
  54. set
  55. {
  56. _itemsSourceData = value;
  57. tvZsmTree.ItemsSource = _itemsSourceData;
  58. }
  59. }
  60.  
  61. /// <summary>
  62. /// 设置对应Id的项为选中状态
  63. /// </summary>
  64. /// <param name="id"></param>
  65. /// <returns></returns>
  66. public int SetCheckedById(string id, IList<Model.TreeModel> treeList)
  67. {
  68. foreach (var tree in treeList)
  69. {
  70. if (tree.Id.Equals(id))
  71. {
  72. tree.IsChecked = true;
  73. return 1;
  74. }
  75. if (SetCheckedById(id, tree.Children) == 1)
  76. {
  77. return 1;
  78. }
  79. }
  80.  
  81. return 0;
  82. }
  83. /// <summary>
  84. /// 设置对应Id的项为选中状态
  85. /// </summary>
  86. /// <param name="id"></param>
  87. /// <returns></returns>
  88. public int SetCheckedById(string id)
  89. {
  90. foreach (var tree in ItemsSourceData)
  91. {
  92. if (tree.Id.Equals(id))
  93. {
  94. tree.IsChecked = true;
  95. return 1;
  96. }
  97. if (SetCheckedById(id, tree.Children) == 1)
  98. {
  99. return 1;
  100. }
  101. }
  102.  
  103. return 0;
  104. }
  105.  
  106. /// <summary>
  107. /// 获取选中项
  108. /// </summary>
  109. /// <returns></returns>
  110. public IList<Model.TreeModel> CheckedItemsIgnoreRelation()
  111. {
  112.  
  113. return GetCheckedItemsIgnoreRelation(_itemsSourceData);
  114. }
  115.  
  116. /// <summary>
  117. /// 私有方法,忽略层次关系的情况下,获取选中项
  118. /// </summary>
  119. /// <param name="list"></param>
  120. /// <returns></returns>
  121. private IList<Model.TreeModel> GetCheckedItemsIgnoreRelation(IList<Model.TreeModel> list)
  122. {
  123. IList<Model.TreeModel> treeList = new List<Model.TreeModel>();
  124. foreach (var tree in list)
  125. {
  126. if (tree.IsChecked)
  127. {
  128. treeList.Add(tree);
  129. }
  130. foreach (var child in GetCheckedItemsIgnoreRelation(tree.Children))
  131. {
  132. treeList.Add(child);
  133. }
  134. }
  135. return treeList;
  136. }
  137.  
  138. /// <summary>
  139. /// 选中所有子项菜单事件
  140. /// </summary>
  141. /// <param name="sender"></param>
  142. /// <param name="e"></param>
  143. private void menuSelectAllChild_Click(object sender, RoutedEventArgs e)
  144. {
  145. if (tvZsmTree.SelectedItem != null)
  146. {
  147. Model.TreeModel tree = (Model.TreeModel)tvZsmTree.SelectedItem;
  148. tree.IsChecked = true;
  149. tree.SetChildrenChecked(true);
  150. }
  151. }
  152.  
  153. /// <summary>
  154. /// 全部展开菜单事件
  155. /// </summary>
  156. /// <param name="sender"></param>
  157. /// <param name="e"></param>
  158. private void menuExpandAll_Click(object sender, RoutedEventArgs e)
  159. {
  160. foreach (Model.TreeModel tree in tvZsmTree.ItemsSource)
  161. {
  162. tree.IsExpanded = true;
  163. tree.SetChildrenExpanded(true);
  164. }
  165. }
  166.  
  167. /// <summary>
  168. /// 全部折叠菜单事件
  169. /// </summary>
  170. /// <param name="sender"></param>
  171. /// <param name="e"></param>
  172. private void menuUnExpandAll_Click(object sender, RoutedEventArgs e)
  173. {
  174. foreach (Model.TreeModel tree in tvZsmTree.ItemsSource)
  175. {
  176. tree.IsExpanded = false;
  177. tree.SetChildrenExpanded(false);
  178. }
  179. }
  180.  
  181. /// <summary>
  182. /// 全部选中事件
  183. /// </summary>
  184. /// <param name="sender"></param>
  185. /// <param name="e"></param>
  186. private void menuSelectAll_Click(object sender, RoutedEventArgs e)
  187. {
  188. foreach (Model.TreeModel tree in tvZsmTree.ItemsSource)
  189. {
  190. tree.IsChecked = true;
  191. tree.SetChildrenChecked(true);
  192. }
  193. }
  194.  
  195. /// <summary>
  196. /// 全部取消选中
  197. /// </summary>
  198. /// <param name="sender"></param>
  199. /// <param name="e"></param>
  200. private void menuUnSelectAll_Click(object sender, RoutedEventArgs e)
  201. {
  202. foreach (Model.TreeModel tree in tvZsmTree.ItemsSource)
  203. {
  204. tree.IsChecked = false;
  205. tree.SetChildrenChecked(false);
  206. }
  207. }
  208.  
  209. /// <summary>
  210. /// 鼠标右键事件
  211. /// </summary>
  212. /// <param name="sender"></param>
  213. /// <param name="e"></param>
  214. private void TreeViewItem_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
  215. {
  216. TreeViewItem item = VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem;
  217. if (item != null)
  218. {
  219. item.Focus();
  220. e.Handled = true;
  221. }
  222. }
  223. static DependencyObject VisualUpwardSearch<T>(DependencyObject source)
  224. {
  225. while (source != null && source.GetType() != typeof(T))
  226. source = VisualTreeHelper.GetParent(source);
  227.  
  228. return source;
  229. }
  230. }
  231. }

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

  1. xmlns:my="clr-namespace:Com.FMS.View.UserControls"
  1. <!--使用控件-->
    <my:ZsmTreeView x:Name="ztvModule" /> 
为控件赋值:

  1. ztvModule.ItemsSourceData = treeList;//treeList为IList<TreeModel>类型

显示效果:

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

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

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

    1.使用数据模板对TreeViewItem进行更改 2.xaml中重写TreeviewItem的控件模板 3.继承TreeViewItem(TreeView中的元素),后台进行控件重写.(介绍此方法) ...

  2. WPF 带CheckBox、图标的TreeView(转)

    在WPF实际项目开发的时候,经常会用到带CheckBox的TreeView,虽然微软在WPF的TreeView中没有提供该功能,但是微软在WPF中提供强大的ItemTemplate模板功能和自定义样式 ...

  3. iOS使用带字体图标的UIButton(支持各种方向)

    简书地址:http://www.jianshu.com/p/1c288440754d demo地址:https://github.com/Brances/ZMProject

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

    wpf里面实现层次绑定主要使用HierarchicalDataTemplate,这里主要谈一谈带checkbox的treeview,具体效果见 wpf企业级开发中的几种常见业务场景. 先来看一下我的控 ...

  5. 潜移默化学会WPF(难点控件treeview)--改造TreeView(CheckBox多选择版本),递归绑定数据

    原文:潜移默化学会WPF(难点控件treeview)--改造TreeView(CheckBox多选择版本),递归绑定数据 目前自己对treeview的感慨很多 今天先讲 面对这种 表结构的数据 的其中 ...

  6. Android实现带图标的ListView

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/bear_huangzhen/article/details/23991119 Android实现带图 ...

  7. Silverlight TreeView 带 checkbox和图片

    前段时间做Silverlight TreeView 控件,但是要带checkbox和图片,在网上到处找相关的例子,效果图如下 xaml代码 <UserControl x:Class=" ...

  8. Qt 怎样生成带图标的exe

    一.问题描述 当我们在 Windows 下用 VS 生成 exe 程序时,如果窗口程序指定了图标,那么生成的 exe 程序便是指定的图标模样. 但是,当使用 Qt Creator 编译程序却不同.即使 ...

  9. WPF中Expander控件样式,ListBox的样式(带checkbox)恢复

    Expander控件样式: <ControlTemplate x:Key="ExpanderToggleButton" TargetType="ToggleButt ...

随机推荐

  1. MySQL数据库的优化-运维架构师必会高薪技能,笔者近六年来一线城市工作实战经验

    原文地址:http://liangweilinux.blog.51cto.com/8340258/1728131 首先在此感谢下我的老师年一线实战经验,我当然不能和我的老师平起平坐,得到老师三分之一的 ...

  2. t-sql 中between and 的一种写法

    t-sql 中between and 的一种写法: where GETDATE() BETWEEN BeginDateTime AND EndDateTime; BeginDateTime,EndDa ...

  3. puppet任务计划

  4. Python运行机制

    闲来无事,简单画了一下Python的运行机制,纯属娱乐:

  5. Yii Framework 开发教程Zii组件-Tabs示例

    有关Yii Tab类: http://www.yiichina.com/api/CTabView http://www.yiichina.com/api/CJuiTabs http://blog.cs ...

  6. dp hdu-4433 locker

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4433 题目大意: 给两个长度相等的数字串s1,s2.每次操作可以把连续的最多三位都+1或-1,如果超 ...

  7. CONTROLS: <> TYPE TABLEVIEW USING SCREEN<>.在 ABAP/4 中声明表格 控制

    在 ABAP/4 中声明表格 控制 在屏幕中使 用表格控制 时,必须在 ABAP/4 程序中同时 声明表格控 制结构和表 格控制字段 . 例如: TABLES:   SFLIGHT. CONTROLS ...

  8. 笔记本开了WIFI之后只能上QQ,上不了网页的解决方法

    前几天拉了宽带之后,开了WIFI,发现WIFI能上网,但是电脑就上不了网页. 把本地连接的DNS指定一下,(电信)指定为202.102.192.68

  9. easyui常用控件样式收藏

    CSS类定义: div easyui-window                               window窗口样式 属性如下: 1)       modal:是否生成模态窗口.tru ...

  10. PYTHON queue

    http://blog.csdn.net/bravezhe/article/details/8588437