需求背景:
当我们用到权限菜单栏时权限菜单栏属于递归效果,我们需要用到TreeView+CheckBox进行组合复选开发时,我们需要解决此类问题时怎么办,那么就引出今天的小笔记内容
实现方式:
下载MVVM框架以及Newtonsoft,这时候可能大家会觉得奇怪,为什么还会用到Json,大家直接看代码,我每一步骤都很详细,代码可直接粘贴,让大家爽一爽
1、创建模型 CheckModel
1 /// <summary> 2 /// 模型可进行序列化 3 /// </summary> 4 [Serializable] 5 public class CheckModel : BindableBase 6 { 7 public CheckModel() 8 { 9 10 }11 private bool? _IsSelected=false;12 public bool? IsSelected13 {14 get { return _IsSelected; }15 set {16 if (SetProperty(ref _IsSelected, value))17 {18 SelectCheck(value, true, true);19 }20 }21 }22 /// <summary>23 /// 设置全选状态24 /// </summary>25 /// <param name="value"></param>26 /// <param name="checkedChildren"></param>27 /// <param name="checkedParent"></param>28 private void SelectCheck(bool? value, bool checkedChildren, bool checkedParent)29 {30 if (checkedChildren && value.HasValue && ChildList != null)31 foreach (var item in ChildList)32 {33 item.SelectCheck(value, true, false);34 }35 if (checkedParent && this.Parent != null)//父类模型不为空就进行状态修改36 this.Parent.CheckParentCheckState();37 IsSelected = value;38 }39 /// <summary>40 /// 设置父类选中状态41 /// </summary>42 private void CheckParentCheckState()43 {44 bool? _currentState = this._IsSelected;//临时存储当前选中状态45 bool? _firstState = null;//刚开始预设为选中状态为空46 47 for (int i = 0; i < this.ChildList.Count(); i++)48 {49 bool? childrenState = this.ChildList[i].IsSelected;//抓起子集合选中状态50 if (i == 0)//如果为第一次循环,将子集选中状态赋给预设状态51 {52 _firstState = childrenState;53 }54 else if (_firstState != childrenState)//如果不是第一次循环将预设状态,也就是将父类选中站台标记为空(空代表子集又被选中)55 {56 _firstState = null;57 }58 }59 if (_firstState != null) _currentState = _firstState;//如果预设的状态不为空,将预设状态给临时存储当前选中状态60 SelectCheck(_firstState, false, true);//开始设置选中状态61 }62 63 private string _Title;64 public string Title65 {66 get { return _Title; }67 set { SetProperty(ref _Title, value); }68 }69 /// <summary>70 /// 这一点很关键,解决Json序列化循环依赖问题71 /// </summary>72 [JsonIgnore]73 private CheckModel _Parent;74 [JsonIgnore]75 public CheckModel Parent76 {77 get { return _Parent; }78 set { SetProperty(ref _Parent, value); }79 }80 private ObservableCollection<CheckModel> _ChildList=new ObservableCollection<CheckModel>();81 public ObservableCollection<CheckModel> ChildList82 {83 get { return _ChildList; }84 set { SetProperty(ref _ChildList, value); }85 }86 }
2、创建ViewModel
1 public class MainWindowViewModel : BindableBase 2 { 3 public MainWindowViewModel() 4 { 5 CheckModel model = new CheckModel(); 6 model.Title = "目录"; 7 model.ChildList = new ObservableCollection<CheckModel>(); 8 ListData.Add(model); 9 CheckModel chmodel = new CheckModel();10 chmodel.Title = "目录1";11 chmodel.Parent = model; 12 CheckModel chmodel_1 = new CheckModel();13 chmodel_1.Title = "目录1-1";14 chmodel_1.Parent = chmodel;15 chmodel.ChildList.Add(chmodel_1);16 model.ChildList.Add(chmodel);17 CheckModel chmodel2 = new CheckModel();18 chmodel2.Title = "目录2";19 chmodel2.Parent = model;20 model.ChildList.Add(chmodel2);21 }22 private ObservableCollection<CheckModel> _ListData = new ObservableCollection<CheckModel>()23 {24 25 };26 public ObservableCollection<CheckModel> ListData27 {28 get { return _ListData; }29 set { SetProperty(ref _ListData, value); }30 }31 private ObservableCollection<CheckModel> _CheckListData = new ObservableCollection<CheckModel>();32 public ObservableCollection<CheckModel> CheckListData33 {34 get { return _CheckListData; }35 set { SetProperty(ref _CheckListData, value); }36 }37 private DelegateCommand _CheckedCommand;38 public DelegateCommand CheckedCommand =>39 _CheckedCommand ?? (_CheckedCommand = new DelegateCommand(ExecuteCheckedCommand));40 41 void ExecuteCheckedCommand()42 {43 CheckListData.Clear();44 #region 这一点很重要,用过Json解决集合地址引用问题,如果直接进行原有集合抓取选中状态,那么你进行递归筛查时涉及到数据地址引用问题,造成源数据被破环问题,利用Json序列化字符串就可以完美就解决地址引用问题45 string datas = Newtonsoft.Json.JsonConvert.SerializeObject(ListData.ToList());46 ObservableCollection<CheckModel> list = Newtonsoft.Json.JsonConvert.DeserializeObject<ObservableCollection<CheckModel>>(datas);47 CheckListData = new ObservableCollection<CheckModel>(GetCheckedItems(list));48 #endregion49 //#region 还原上面描述场景50 //CheckListData = new ObservableCollection<CheckModel>(GetCheckedItems(ListData));51 //#endregion52 }53 /// <summary>54 /// 获取选中项55 /// </summary>56 /// <param name="tree">需要递归的集合</param>57 private ObservableCollection<CheckModel> GetCheckedItems(ObservableCollection<CheckModel> tree)58 {59 //用于存储抓取的选中临时数据60 ObservableCollection<CheckModel> list = new ObservableCollection<CheckModel>();61 if (tree.ToList().Count > 0)62 {63 foreach (var item in tree)64 {65 //检测选中状态66 if (item.IsSelected != false) {67 //防呆,检测集合空值。若为空值 直接进行添加当前对象68 if (item.ChildList!=null)69 {70 //很重要->>>递归抓取下一层集合数据赋予当前模型集合71 item.ChildList = GetCheckedItems(item.ChildList);72 //填充当前抓取的对象73 list.Add(item);74 }75 else {76 /// 填充当前抓取的对象77 list.Add(item);78 }79 }80 }81 }82 return list;83 }84 }
备注:
原创文章禁止转载 2022-02-18