首先声明,这个大部分参照了2位大神,我做了一小部分改动。原来的控件选择状态只能是false或true,我加入了第三种状态Null,就是部分选中状态。另外在Model 里面加了一个 Tag属性,将IList改为ObservableCollection<T> 还完善了ItemSource 为null点右键菜单报错的判断。
原文地址是http://www.cnblogs.com/zsmhhfy/archive/2013/03/18/2965755.html
http://blog.csdn.net/kunoy/article/details/11603933
主要改动是SetParentChecked 和SetChildrenChecked 这两个方法,把Model的IsChecked由bool 类型改为 bool?
public void SetParentChecked() { if (Parent != null) { if (Parent.Children.Where(c => c.IsChecked == null).Count() > 0) { Parent.IsChecked = null; } else if (Parent.Children.Where(c => c.IsChecked == true).Count() == 0) { Parent.IsChecked = false; } else if (Parent.Children.Where(c => c.IsChecked == true).Count() == Parent.Children.Count) { Parent.IsChecked = true; } else if (Parent.Children.Where(c => c.IsChecked == true).Count() < Parent.Children.Count) { Parent.IsChecked = null; } if (Parent.Parent != null) { Parent.SetParentChecked(); } } }
所有改动后的代码如下
XAML
<UserControl x:Class="FYJ.Windows.Controls.CustomTreeView" 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:FYJ.Windows.Controls" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"> <Grid> <DockPanel> <Border> <TreeView Name="tvZsmTree"> <TreeView.ContextMenu> <ContextMenu> <MenuItem Name="menuExpandAll" Header="全部展开" Click="menuExpandAll_Click"> <MenuItem.Icon> <Image Source="Images/16_16/folder_open_arrow.png" /> </MenuItem.Icon> </MenuItem> <MenuItem Name="menuUnExpandAll" Header="全部折叠" Click="menuUnExpandAll_Click"> <MenuItem.Icon> <Image Source="Images/16_16/folder_close_arrow.png" /> </MenuItem.Icon> </MenuItem> <MenuItem Name="menuSelectAll" Header="全部选中" Click="menuSelectAll_Click"> <MenuItem.Icon> <Image Source="Images/16_16/tick.png" /> </MenuItem.Icon> </MenuItem> <MenuItem Name="menuUnSelectAll" Header="全部取消" Click="menuUnSelectAll_Click"> <MenuItem.Icon> <Image Source="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}" Click="treeNode_Click"> <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="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>
Model
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel; using System.Collections.ObjectModel; namespace FYJ.Windows.Controls { 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 ObservableCollection<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"); } } } /// <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() { if (Children != null && Children.Count > 0 && IsChecked != null) { foreach (TreeModel child in Children) { child.IsChecked = IsChecked; if (child.Children != null && Children.Count > 0) { child.SetChildrenChecked(); } } } } public void SetChildrenChecked(bool isCheck) { if (Children != null && Children.Count > 0) { foreach (TreeModel child in Children) { child.IsChecked = isCheck; if (child.Children != null && Children.Count > 0) { child.SetChildrenChecked(isCheck); } } } } /// <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)); } } #region 新加 /// <summary> /// 附加属性 /// </summary> /// fangyj public object Tag { get; set; } public void SetParentChecked() { if (Parent != null) { if (Parent.Children.Where(c => c.IsChecked == null).Count() > 0) { Parent.IsChecked = null; } else if (Parent.Children.Where(c => c.IsChecked == true).Count() == 0) { Parent.IsChecked = false; } else if (Parent.Children.Where(c => c.IsChecked == true).Count() == Parent.Children.Count) { Parent.IsChecked = true; } else if (Parent.Children.Where(c => c.IsChecked == true).Count() < Parent.Children.Count) { Parent.IsChecked = null; } if (Parent.Parent != null) { Parent.SetParentChecked(); } } } #endregion } }
XAML后台
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 FYJ.Windows.Controls { /// <summary> /// ZsmTreeView.xaml 的交互逻辑 /// </summary> public partial class CustomTreeView : UserControl { #region 私有变量属性 /// <summary> /// 控件数据 /// </summary> private IList<TreeModel> _itemsSourceData; #endregion /// <summary> /// 构造 /// </summary> public CustomTreeView() { InitializeComponent(); } /// <summary> /// 控件数据 /// </summary> public IList<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<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<TreeModel> CheckedItemsIgnoreRelation() { return GetCheckedItemsIgnoreRelation(_itemsSourceData); } /// <summary> /// 私有方法,忽略层次关系的情况下,获取选中项 /// </summary> /// <param name="list"></param> /// <returns></returns> private IList<TreeModel> GetCheckedItemsIgnoreRelation(IList<TreeModel> list) { IList<TreeModel> treeList = new List<TreeModel>(); foreach (var tree in list) { if (tree.IsChecked==true) { 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) { TreeModel tree = (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) { if (tvZsmTree.ItemsSource!=null) { foreach (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) { if (tvZsmTree.ItemsSource != null) { foreach (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) { if (tvZsmTree.ItemsSource != null) { foreach (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) { if (tvZsmTree.ItemsSource != null) { foreach (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; } private void treeNode_Click(object sender, RoutedEventArgs e) { TreeViewItem item = VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem; if (item != null) { item.Focus(); if (tvZsmTree.SelectedItem != null) { TreeModel tree = (TreeModel)tvZsmTree.SelectedItem; tree.SetChildrenChecked(); tree.SetParentChecked(); } e.Handled = true; } } } }
12/3/2016 3:55:31 PM 120.85.244....
结果发给客户方法恢复方法