175 lines
5.3 KiB
C#
175 lines
5.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
|
|
namespace FasdDesktopUi.Basics.Models
|
|
{
|
|
public class HierarchicalSelectionItem : INotifyPropertyChanged
|
|
{
|
|
private bool _isExpanded;
|
|
|
|
public string Id { get; set; }
|
|
public string DisplayName { get; set; }
|
|
public string ParentId { get; set; }
|
|
public string ParentDisplayName { get; set; }
|
|
|
|
public ObservableCollection<HierarchicalSelectionItem> Children { get; } = new ObservableCollection<HierarchicalSelectionItem>();
|
|
|
|
public HierarchicalSelectionItem Parent { get; private set; }
|
|
|
|
public bool IsExpanded
|
|
{
|
|
get => _isExpanded;
|
|
set
|
|
{
|
|
if (_isExpanded == value)
|
|
return;
|
|
_isExpanded = value;
|
|
OnPropertyChanged(nameof(IsExpanded));
|
|
}
|
|
}
|
|
|
|
public string FullPath
|
|
{
|
|
get
|
|
{
|
|
if (Parent == null || string.IsNullOrWhiteSpace(Parent.DisplayName))
|
|
return DisplayName ?? string.Empty;
|
|
|
|
if (string.IsNullOrWhiteSpace(DisplayName))
|
|
return Parent.FullPath;
|
|
|
|
return $"{Parent.FullPath} / {DisplayName}";
|
|
}
|
|
}
|
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
protected void OnPropertyChanged(string propertyName) =>
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
|
|
public void AddChild(HierarchicalSelectionItem child)
|
|
{
|
|
if (child == null)
|
|
return;
|
|
|
|
child.Parent = this;
|
|
Children.Add(child);
|
|
}
|
|
|
|
public void ClearChildren()
|
|
{
|
|
foreach (var child in Children)
|
|
child.Parent = null;
|
|
|
|
Children.Clear();
|
|
}
|
|
|
|
public void SortChildrenRecursive()
|
|
{
|
|
if (Children == null || Children.Count == 0)
|
|
return;
|
|
|
|
var orderedChildren = Children
|
|
.OrderBy(child => child.DisplayName, StringComparer.CurrentCultureIgnoreCase)
|
|
.ToList();
|
|
|
|
Children.Clear();
|
|
|
|
foreach (var child in orderedChildren)
|
|
{
|
|
Children.Add(child);
|
|
child.SortChildrenRecursive();
|
|
}
|
|
}
|
|
|
|
public IEnumerable<HierarchicalSelectionItem> SelfAndDescendants()
|
|
{
|
|
yield return this;
|
|
foreach (var child in Children)
|
|
{
|
|
foreach (var descendant in child.SelfAndDescendants())
|
|
yield return descendant;
|
|
}
|
|
}
|
|
|
|
public void SetExpandedRecursive(bool isExpanded)
|
|
{
|
|
IsExpanded = isExpanded;
|
|
|
|
foreach (var child in Children)
|
|
child.SetExpandedRecursive(isExpanded);
|
|
}
|
|
|
|
public HierarchicalSelectionItem CloneWithoutChildren()
|
|
{
|
|
return new HierarchicalSelectionItem
|
|
{
|
|
Id = Id,
|
|
DisplayName = DisplayName,
|
|
ParentId = ParentId,
|
|
ParentDisplayName = ParentDisplayName
|
|
};
|
|
}
|
|
|
|
public HierarchicalSelectionItem CloneBranch(Func<HierarchicalSelectionItem, bool> predicate)
|
|
{
|
|
bool matches = predicate?.Invoke(this) ?? true;
|
|
var matchingChildren = new List<HierarchicalSelectionItem>();
|
|
|
|
foreach (var child in Children)
|
|
{
|
|
var childClone = child.CloneBranch(predicate);
|
|
if (childClone != null)
|
|
matchingChildren.Add(childClone);
|
|
}
|
|
|
|
if (!matches && matchingChildren.Count == 0)
|
|
return null;
|
|
|
|
var clone = CloneWithoutChildren();
|
|
foreach (var childClone in matchingChildren)
|
|
clone.AddChild(childClone);
|
|
|
|
return clone;
|
|
}
|
|
|
|
public static ObservableCollection<HierarchicalSelectionItem> BuildTree(IEnumerable<HierarchicalSelectionItem> items)
|
|
{
|
|
if (items == null)
|
|
return new ObservableCollection<HierarchicalSelectionItem>();
|
|
|
|
var lookup = items
|
|
.Where(item => !string.IsNullOrWhiteSpace(item?.Id))
|
|
.GroupBy(item => item.Id)
|
|
.Select(group => group.First())
|
|
.ToDictionary(item => item.Id);
|
|
|
|
foreach (var entry in lookup.Values)
|
|
entry.ClearChildren();
|
|
|
|
var roots = new List<HierarchicalSelectionItem>();
|
|
|
|
foreach (var item in lookup.Values)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(item.ParentId) && lookup.TryGetValue(item.ParentId, out var parent))
|
|
{
|
|
parent.AddChild(item);
|
|
}
|
|
else
|
|
{
|
|
item.Parent = null;
|
|
roots.Add(item);
|
|
}
|
|
}
|
|
|
|
foreach (var root in roots)
|
|
root.SortChildrenRecursive();
|
|
|
|
return new ObservableCollection<HierarchicalSelectionItem>(
|
|
roots.OrderBy(root => root.DisplayName, StringComparer.CurrentCultureIgnoreCase));
|
|
}
|
|
}
|
|
}
|