首先声明,这个大部分参照了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?
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | <UserControl x:Class= "FYJ.Windows.Controls.CustomTreeView" 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
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | 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后台
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | 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 ; } } } } |
2/1/2016 9:42:06 PM 120.25.144....
正急需,请帮发一份(405404410@qq.com)谢谢