מבנה נתונים גלובלי עבור Checked TreeView ב-Wpf
-
כידוע, הדרך הטובה ביותר להתנהל עם TreeView ב-WPF היא עם מבנה נתונים הררכי, ו-HierarchicalDataTemplate ב-WPF נבנה במיוחד למטרה זו.
אחרי שמצאתי את עצמי בפעם השלישית בונה מבנה נתונים עבור Checked TreeView (ראה תמונה), החלטתי לשבת כמה דקות ולבנות משהו יותר גלובלי שיאפשר לי להשתמש בו גם בעתיד. הרעיון הוא לייצר מחלקה בסיסית המכילה את כל מה שדרוש עבור מטרה זו, כך שאוכל לרשת אותה ולהשתמש בה עבור כל מבנה נתונים הררכי באופן כללי עם הדרישה הזו של Checked TreeView.שימו לב! אני הגדרתי את ה-Default של ה-IsChecked כ-false ייתכן ותרצו לשנות את זה ל-true תלוי באמפלמנטציה שלכם.
אם לא הבנתם את הנושא דיו והוא מעניין אתכם? אנא קיראו כתבה זו כהקדמה:
https://www.codeproject.com/Articles/26288/Simplifying-the-WPF-TreeView-by-Using-the-ViewModeלהלן הקוד:
///sample usage //public class MyCheckedItem : TreeItemBase<MyCheckedItem> //{ // // Custom properties if needed //}
using System.Collections.Generic; using System.Linq; namespace WpfLib.ViewModels { public class CheckedTreeItemBase<T> : TreeItemBase<T> where T : CheckedTreeItemBase<T> { bool? _isChecked = false; public bool? IsChecked { get => _isChecked; set => SetCheckedValue(value, true); } public void SetCheckedValue(bool? isChecked, bool updateChildren) { if (SetProperty(ref _isChecked, isChecked, nameof(IsChecked))) { if (updateChildren && Items != null) { foreach (var child in Items) { if (child.IsChecked != isChecked) child.IsChecked = isChecked == true; } } if (Parent != null) { var siblings = Parent.Items; var parentCheckedValue = siblings.All(c => c.IsChecked == true) ? true : siblings.All(c => c.IsChecked == false) ? (bool?)false : null; Parent.SetCheckedValue(parentCheckedValue, false); } } } public IEnumerable<T> EnumerateCheckedItems() { if (Items != null) { foreach (var child in Items) { if (child.IsChecked == true) yield return child; foreach (var item in child.EnumerateCheckedItems()) yield return item; } } } } }
המודל יורש ממודל treeitembase שמשמש כבסיס לכל מודל היררכי בעץ נתונים
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Text.Json.Serialization; namespace WpfLib.ViewModels { public class TreeItemBase<T> : ViewModelBase where T : TreeItemBase<T> { string _name; ObservableCollection<T> _items = new ObservableCollection<T>(); [JsonIgnore] public T Parent { get; set; } public virtual string Name { get => _name; set => SetProperty(ref _name, value); } public ObservableCollection<T> Items { get => _items; set => SetProperty(ref _items, value); } public override string ToString() => Name; public void AddChild(T item) { if (Items == null) Items = new ObservableCollection<T>(); Items.Add(item); item.Parent = (T)this; } public IEnumerable<T> EnumerateItems() { if (_items == null) yield break; foreach (var item in _items) { yield return item; foreach (var child in item.EnumerateItems()) yield return child; } } } }
המודל יורש מודל אחר שימושי בשם ViewModelBase המהווה בסיס טוב עבור כל viewModle ב-Wpf
using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; namespace MyModels { public class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null) { if (EqualityComparer<T>.Default.Equals(field, value)) return false; field = value; OnPropertyChanged(propertyName); return true; } } }
-
P pcinfogmach התייחס לנושא זה ב