You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Connected.Components/Components/TreeView/TreeView.razor.cs

245 lines
6.7 KiB

2 years ago
using System.Diagnostics.CodeAnalysis;
using Connected.Annotations;
using Connected.Extensions;
using Connected.Utilities;
using Microsoft.AspNetCore.Components;
namespace Connected.Components;
public partial class TreeView<T> : UIComponent
{
private TreeViewItem<T> _selectedValue;
private HashSet<TreeViewItem<T>> _selectedValues;
private List<TreeViewItem<T>> _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();
/// <summary>
/// The color of the selected treeviewitem.
/// </summary>
[Parameter]
[Category(CategoryTypes.TreeView.Selecting)]
public ThemeColor Color { get; set; } = ThemeColor.Primary;
/// <summary>
/// Check box color if multiselection is used.
/// </summary>
[Parameter]
[Category(CategoryTypes.TreeView.Selecting)]
public ThemeColor CheckBoxColor { get; set; }
/// <summary>
/// if true, multiple values can be selected via checkboxes which are automatically shown in the tree view.
/// </summary>
[Parameter]
[Category(CategoryTypes.TreeView.Selecting)]
public bool MultiSelection { get; set; }
/// <summary>
/// if true, multiple values can be selected via checkboxes which are automatically shown in the tree view.
/// </summary>
[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; }
/// <summary>
/// If true, clicking anywhere on the item will expand it, if it has childs.
/// </summary>
[Parameter]
[Category(CategoryTypes.TreeView.ClickAction)]
public bool ExpandOnClick { get; set; }
/// <summary>
/// If true, double clicking anywhere on the item will expand it, if it has childs.
/// </summary>
[Parameter]
[Category(CategoryTypes.TreeView.ClickAction)]
public bool ExpandOnDoubleClick { get; set; }
/// <summary>
/// Hover effect for item's on mouse-over.
/// </summary>
[Parameter]
[Category(CategoryTypes.TreeView.Appearance)]
public bool Hover { get; set; }
/// <summary>
/// Hover effect for item's on mouse-over.
/// </summary>
[ExcludeFromCodeCoverage]
[Obsolete("Use Hover instead.", true)]
[Parameter]
public bool CanHover
{
get => Hover;
set => Hover = value;
}
/// <summary>
/// If true, compact vertical padding will be applied to all treeview items.
/// </summary>
[Parameter]
[Category(CategoryTypes.TreeView.Appearance)]
public bool Dense { get; set; }
/// <summary>
/// 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.
/// </summary>
[Parameter]
[Category(CategoryTypes.TreeView.Appearance)]
public string Height { get; set; }
/// <summary>
/// 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.
/// </summary>
[Parameter]
[Category(CategoryTypes.TreeView.Appearance)]
public string MaxHeight { get; set; }
/// <summary>
/// Setting a width the treeview. You can set this to any CSS value that the attribute 'height' accepts, i.e. 500px.
/// </summary>
[Parameter]
[Category(CategoryTypes.TreeView.Appearance)]
public string Width { get; set; }
/// <summary>
/// If true, treeview will be disabled and all its childitems.
/// </summary>
[Parameter]
[Category(CategoryTypes.TreeView.Behavior)]
public bool Disabled { get; set; }
[Parameter]
[Category(CategoryTypes.TreeView.Data)]
public HashSet<T> Items { get; set; }
[ExcludeFromCodeCoverage]
[Obsolete("Use SelectedValueChanged instead.", true)]
[Parameter]
public EventCallback<T> ActivatedValueChanged
{
get => SelectedValueChanged;
set => SelectedValueChanged = value;
}
/// <summary>
/// Called whenever the selected value changed.
/// </summary>
[Parameter] public EventCallback<T> SelectedValueChanged { get; set; }
/// <summary>
/// Called whenever the selectedvalues changed.
/// </summary>
[Parameter] public EventCallback<HashSet<T>> SelectedValuesChanged { get; set; }
/// <summary>
/// Child content of component.
/// </summary>
[Parameter]
[Category(CategoryTypes.TreeView.Data)]
public RenderFragment ChildContent { get; set; }
/// <summary>
/// ItemTemplate for rendering children.
/// </summary>
[Parameter]
[Category(CategoryTypes.TreeView.Data)]
public RenderFragment<T> ItemTemplate { get; set; }
[CascadingParameter] TreeView<T> MudTreeRoot { get; set; }
[Parameter]
[Category(CategoryTypes.TreeView.Data)]
public Func<T, Task<HashSet<T>>> 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<T> 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<TreeViewItem<T>>();
//collect selected items
_selectedValues.Clear();
foreach (var item in _childItems)
{
foreach (var selectedItem in item.GetSelectedItems())
{
_selectedValues.Add(selectedItem);
}
}
return SelectedValuesChanged.InvokeAsync(new HashSet<T>(_selectedValues.Select(i => i.Value)));
}
internal void AddChild(TreeViewItem<T> item) => _childItems.Add(item);
}