wpf裏面實現層次綁定主要使用HierarchicalDataTemplate,這裏主要談一談帶checkbox的treeview,具體效果見 wpf企業級開發中的幾種常見業務場景。html
先來看一下個人控件綁定,我這裏實現的是模塊權限的編輯。具體效果就是選中一個節點,後代節點、祖代節點狀態都會發生相應變化,具體變化邏輯你們都懂的,描述起來很羅嗦。this
<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的使用。spa
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; } }