wpf里面实现层次绑定主要使用HierarchicalDataTemplate,这里主要谈一谈带checkbox的treeview,具体效果见 wpf企业级开发中的几种常见业务场景。
先来看一下我的控件绑定,我这里实现的是模块权限的编辑。具体效果就是选中一个节点,后代节点、祖代节点状态都会发生相应变化,具体变化逻辑大家都懂的,描述起来很罗嗦。
<TreeView Name="TreeView_Right" ItemsSource="{Binding ModuleRight}"> <TreeView.ItemTemplate> <HierarchicalDataTemplate DataType="{x:Type localModel:ModuleRight}" ItemsSource="{Binding ModuleChildren}"> <CheckBox IsThreeState="{Binding IsThreeState}" Content="{Binding MenuName}" IsChecked="{Binding IsChecked}" IsEnabled="{Binding IsEnabled}"/> </HierarchicalDataTemplate> </TreeView.ItemTemplate> <TreeView.ItemContainerStyle> <Style TargetType="TreeViewItem" BasedOn="{StaticResource TreeViewItemStyle}"> <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=OneWay}"/> </Style> </TreeView.ItemContainerStyle> </TreeView>
下面是对应的绑定类,仅供参考。这里需要说明的就是,IsChecked每次变化时都要递归去修改父节点、子节点的IsChecked属性,其他的跟普通的treeview绑定没什么区别,读者若有不明之处可自行去MSDN上查看treeview的使用。
public class ModuleRight : NotifyModelBase { private ModuleRight _parent; public ModuleRight Parent { get { return _parent; } set { _parent = value; OnPropertyChanged("Parent"); } } private string _menuName; public string MenuName { get { if (AppSetting.GetValue("language") == "en_us") return MenuName_EN; return _menuName; } set { _menuName = value; } } public string MenuName_EN { get; set; } public string ClassName { get; set; } private List<ModuleRight> _moduleChildren; public List<ModuleRight> ModuleChildren { get { return _moduleChildren ?? (_moduleChildren = new List<ModuleRight>()); } set { _moduleChildren = value; } } private int _rightValue; public int RightValue { get { return _rightValue; } set { _rightValue = value; } } private bool _isThreeState; public bool IsThreeState { get { return _isThreeState; } set { _isThreeState = value; OnPropertyChanged("IsThreeState"); } } private bool _isEnabled = true; public bool IsEnabled { get { return _isEnabled; } set { _isEnabled = value; OnPropertyChanged("IsEnabled"); } } private bool? _isChecked = false; public bool? IsChecked { get { return _isChecked; } set { SetIsChecked(value, true, true); } } public bool IsExpanded { get { return _isChecked != false; } } public void SetIsChecked(bool? value, bool updateChildren, bool updateParent) { _isChecked = value; if (updateChildren && _isChecked.HasValue)//设置后代节点的选中状态 { ModuleChildren.ForEach(c => c.SetIsChecked(_isChecked, true, false)); } if (updateParent && Parent != null && Parent.IsThreeState)//设置祖代节点的选中状态 { Parent.VerifyCheckState(); } OnPropertyChanged("IsChecked"); } public void VerifyCheckState() { bool? state = true; for (int i = 0; i < ModuleChildren.Count; i++) { bool? current = ModuleChildren[i].IsChecked; if (current == null) { state = null; break; } else { if (i < ModuleChildren.Count - 1 && ModuleChildren[i].IsChecked != ModuleChildren[i + 1].IsChecked) { state = null; break; } } } if (state != null) state = ModuleChildren[0].IsChecked; SetIsChecked(state, false, true); } public ModuleRight() { } public ModuleRight(string menuName, string menuName_en, string className) { this.MenuName = menuName; this.MenuName_EN = menuName_en; this.ClassName = className; } }