WPF 可多选的树TreeView

因工作需要,自定义一个树形控件,支持多选并且父节点选中子节点全部选中,反之全部取消


    
            
            
                
                    
                    
                    
                    
                    
                
            
            
        
    
        
        
    


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Text;

namespace treeview
{
    public class NotifyPropertyBase : INotifyPropertyChanged
    {
        public void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }

    /// 
    /// 扩展方法
    /// 避免硬编码问题
    /// 
    public static class NotifyPropertyBaseEx
    {
        public static void SetProperty(this T tvm, Expression> expre) where T : NotifyPropertyBase, new()
        {
            string _pro = CommonFun.GetPropertyName(expre);
            tvm.OnPropertyChanged(_pro);
        }//为什么扩展方法必须是静态的
    }

    public class CommonFun
    {
        /// 
        /// 返回属性名
        /// 
        /// 
        /// 
        /// 
        /// 
        public static string GetPropertyName(Expression> expr)
        {
            string _propertyName = "";
            if (expr.Body is MemberExpression)
            {
                _propertyName = (expr.Body as MemberExpression).Member.Name;
            }
            else if (expr.Body is UnaryExpression)
            {
                _propertyName = ((expr.Body as UnaryExpression).Operand as MemberExpression).Member.Name;
            }
            return _propertyName;
        }
    } 
}
using System;
using System.Collections.Generic;
using System.Text;

namespace treeview
{
    public class CommonTreeView : NotifyPropertyBase
    {
        /// 
        /// 父
        /// 
        public CommonTreeView Parent
        {
            get;
            set;
        }

        /// 
        /// 子
        /// 
        public List Children
        {
            get;
            set;
        }

        /// 
        /// 节点的名字
        /// 
        public string NodeName
        {
            get;
            set;
        }

        public bool? _isChecked;
        /// 
        /// CheckBox是否选中
        /// 
        public bool? IsChecked
        {
            get
            {
                return _isChecked;
            }
            set
            {
                SetIsChecked(value, true, true);
            }
        }

        public CommonTreeView(string name)
        {
            this.NodeName = name;
            this.Children = new List();
        }
        public CommonTreeView() { }


        private void SetIsChecked(bool? value, bool checkedChildren, bool checkedParent)
        {
            if (_isChecked == value) return;
            _isChecked = value;
            //选中和取消子类
            if (checkedChildren && value.HasValue && Children != null)
                Children.ForEach(ch => ch.SetIsChecked(value, true, false));

            //选中和取消父类
            if (checkedParent && this.Parent != null)
                this.Parent.CheckParentCheckState();

            //通知更改
            this.SetProperty(x => x.IsChecked);
        }

        /// 
        /// 检查父类是否选 中
        /// 如果父类的子类中有一个和第一个子类的状态不一样父类ischecked为null
        /// 
        private void CheckParentCheckState()
        {
            List checkedItems = new List();
            string checkedNames = string.Empty;
            bool? _currentState = this.IsChecked;
            bool? _firstState = null;
            for (int i = 0; i < this.Children.Count; i++)
            {
                bool? childrenState = this.Children[i].IsChecked;
                if (i == 0)
                {
                    _firstState = childrenState;
                }
                else if (_firstState != childrenState)
                {
                    _firstState = null;
                }
            }
            if (_firstState != null) _currentState = _firstState;
            SetIsChecked(_firstState, false, true);
        }

        /// 
        /// 创建树
        /// 
        /// 
        /// 

        public void CreateTreeWithChildre(CommonTreeView children, bool? isChecked)
        {
            this.Children.Add(children);
            //必须先把孩子加入再为Parent赋值,
            //否则当只有一个子节点时Parent的IsChecked状态会出错

            children.Parent = this;
            children.IsChecked = isChecked;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;

namespace treeview
{
    public class CommonTreeViewModel
    {
        public ObservableCollection myTrees = new ObservableCollection();

        public CommonTreeViewModel() {

            CommonTreeView _myy = new CommonTreeView("CCP");
            MyTrees.Add(_myy);
            CommonTreeView _myy1 = new CommonTreeView("CCP_1");
            _myy.CreateTreeWithChildre(_myy1, true);
            CommonTreeView _myy1_1 = new CommonTreeView("CCP_1.1");
            _myy1.CreateTreeWithChildre(_myy1_1, true);
            CommonTreeView _myy1_2 = new CommonTreeView("CCP_1.1");
            _myy1.CreateTreeWithChildre(_myy1_2, true);

            CommonTreeView _myy2 = new CommonTreeView("CCP_1");
            _myy.CreateTreeWithChildre(_myy2, true);

            _myy2.CreateTreeWithChildre(_myy1_1, true);
            _myy2.CreateTreeWithChildre(_myy1_2, true);
        }

        public ObservableCollection MyTrees
        {
            get { return myTrees; }
            set { myTrees = value; }
        
        }
    }
}
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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 treeview
{
    /// 
    /// Interaction logic for MainWindow.xaml
    /// 
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            CommonTreeViewModel model = new CommonTreeViewModel();
            this.tv.DataContext = model;

        }
    }
}

需要注意的是

1、 集合必须使用ObservableCollection,因为ObservableCollection继承了INotifyPropertyChanged,集合改变时会自动通知改变页面

2、集合MyTrees必须实现Get,Set方法 因为在C#中,写了{get;set;}才是属性,不写就是字段。而Binding的Source是对象,Path必须是属性。

你可能感兴趣的:(WPF,TreeView,WPF,多选节点)