using System.Diagnostics.CodeAnalysis; using Connected.Annotations; using Connected.Extensions; using Connected.Utilities; using Microsoft.AspNetCore.Components; namespace Connected.Components; public partial class TreeView : UIComponent { private TreeViewItem _selectedValue; private HashSet> _selectedValues; private List> _childItems = new(); protected string Classname => new CssBuilder("mud-treeview") .AddClass("mud-treeview-dense", Dense) .AddClass("mud-treeview-hover", Hover) .AddClass($"mud-treeview-selected-{Color.ToDescriptionString()}") .AddClass($"mud-treeview-checked-{CheckBoxColor.ToDescriptionString()}") .AddClass(Class) .Build(); protected string Stylename => new StyleBuilder() .AddStyle($"width", Width, !string.IsNullOrWhiteSpace(Width)) .AddStyle($"height", Height, !string.IsNullOrWhiteSpace(Height)) .AddStyle($"max-height", MaxHeight, !string.IsNullOrWhiteSpace(MaxHeight)) .AddStyle(Style) .Build(); /// /// The color of the selected treeviewitem. /// [Parameter] [Category(CategoryTypes.TreeView.Selecting)] public ThemeColor Color { get; set; } = ThemeColor.Primary; /// /// Check box color if multiselection is used. /// [Parameter] [Category(CategoryTypes.TreeView.Selecting)] public ThemeColor CheckBoxColor { get; set; } /// /// if true, multiple values can be selected via checkboxes which are automatically shown in the tree view. /// [Parameter] [Category(CategoryTypes.TreeView.Selecting)] public bool MultiSelection { get; set; } /// /// if true, multiple values can be selected via checkboxes which are automatically shown in the tree view. /// [ExcludeFromCodeCoverage] [Obsolete("Use MultiSelection instead.", true)] [Parameter] public bool CanSelect { get => MultiSelection; set => MultiSelection = value; } [ExcludeFromCodeCoverage] [Obsolete("MudTreeView now automaticly activates when using SelectedValue.", true)] [Parameter] public bool CanActivate { get; set; } /// /// If true, clicking anywhere on the item will expand it, if it has childs. /// [Parameter] [Category(CategoryTypes.TreeView.ClickAction)] public bool ExpandOnClick { get; set; } /// /// If true, double clicking anywhere on the item will expand it, if it has childs. /// [Parameter] [Category(CategoryTypes.TreeView.ClickAction)] public bool ExpandOnDoubleClick { get; set; } /// /// Hover effect for item's on mouse-over. /// [Parameter] [Category(CategoryTypes.TreeView.Appearance)] public bool Hover { get; set; } /// /// Hover effect for item's on mouse-over. /// [ExcludeFromCodeCoverage] [Obsolete("Use Hover instead.", true)] [Parameter] public bool CanHover { get => Hover; set => Hover = value; } /// /// If true, compact vertical padding will be applied to all treeview items. /// [Parameter] [Category(CategoryTypes.TreeView.Appearance)] public bool Dense { get; set; } /// /// Setting a height will allow to scroll the treeview. If not set, it will try to grow in height. /// You can set this to any CSS value that the attribute 'height' accepts, i.e. 500px. /// [Parameter] [Category(CategoryTypes.TreeView.Appearance)] public string Height { get; set; } /// /// Setting a maximum height will allow to scroll the treeview. If not set, it will try to grow in height. /// You can set this to any CSS value that the attribute 'height' accepts, i.e. 500px. /// [Parameter] [Category(CategoryTypes.TreeView.Appearance)] public string MaxHeight { get; set; } /// /// Setting a width the treeview. You can set this to any CSS value that the attribute 'height' accepts, i.e. 500px. /// [Parameter] [Category(CategoryTypes.TreeView.Appearance)] public string Width { get; set; } /// /// If true, treeview will be disabled and all its childitems. /// [Parameter] [Category(CategoryTypes.TreeView.Behavior)] public bool Disabled { get; set; } [Parameter] [Category(CategoryTypes.TreeView.Data)] public HashSet Items { get; set; } [ExcludeFromCodeCoverage] [Obsolete("Use SelectedValueChanged instead.", true)] [Parameter] public EventCallback ActivatedValueChanged { get => SelectedValueChanged; set => SelectedValueChanged = value; } /// /// Called whenever the selected value changed. /// [Parameter] public EventCallback SelectedValueChanged { get; set; } /// /// Called whenever the selectedvalues changed. /// [Parameter] public EventCallback> SelectedValuesChanged { get; set; } /// /// Child content of component. /// [Parameter] [Category(CategoryTypes.TreeView.Data)] public RenderFragment ChildContent { get; set; } /// /// ItemTemplate for rendering children. /// [Parameter] [Category(CategoryTypes.TreeView.Data)] public RenderFragment ItemTemplate { get; set; } [CascadingParameter] TreeView MudTreeRoot { get; set; } [Parameter] [Category(CategoryTypes.TreeView.Data)] public Func>> ServerData { get; set; } public TreeView() { MudTreeRoot = this; } internal bool IsSelectable { get; private set; } protected override void OnInitialized() { IsSelectable = SelectedValueChanged.HasDelegate; } protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender && MudTreeRoot == this) { await UpdateSelectedItems(); } await base.OnAfterRenderAsync(firstRender); } internal async Task UpdateSelected(TreeViewItem item, bool requestedValue) { if ((_selectedValue == item && requestedValue) || (_selectedValue != item && !requestedValue)) return; if (_selectedValue == item && !requestedValue) { _selectedValue = default; await item.Select(requestedValue); await SelectedValueChanged.InvokeAsync(default); return; } if (_selectedValue != null) { await _selectedValue.Select(false); } _selectedValue = item; await item.Select(requestedValue); await SelectedValueChanged.InvokeAsync(item.Value); } internal Task UpdateSelectedItems() { _selectedValues ??= new HashSet>(); //collect selected items _selectedValues.Clear(); foreach (var item in _childItems) { foreach (var selectedItem in item.GetSelectedItems()) { _selectedValues.Add(selectedItem); } } return SelectedValuesChanged.InvokeAsync(new HashSet(_selectedValues.Select(i => i.Value))); } internal void AddChild(TreeViewItem item) => _childItems.Add(item); }