2021-07-11 18:43:25 +08:00
|
|
|
|
// Licensed to the .NET Foundation under one or more agreements.
|
|
|
|
|
// The .NET Foundation licenses this file to you under the MIT license.
|
|
|
|
|
// See the LICENSE file in the project root for more information.
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Concurrent;
|
2020-06-29 15:39:18 +08:00
|
|
|
|
using System.Collections.Generic;
|
2020-10-09 15:13:32 +08:00
|
|
|
|
using System.Linq;
|
2021-07-11 18:43:25 +08:00
|
|
|
|
using System.Threading.Tasks;
|
2020-06-29 15:39:18 +08:00
|
|
|
|
using Microsoft.AspNetCore.Components;
|
2021-07-11 18:43:25 +08:00
|
|
|
|
using Microsoft.AspNetCore.Components.Web;
|
2020-06-29 15:39:18 +08:00
|
|
|
|
|
|
|
|
|
namespace AntDesign
|
|
|
|
|
{
|
2020-12-30 18:38:35 +08:00
|
|
|
|
public partial class Tree<TItem> : AntDomComponentBase
|
2020-06-29 15:39:18 +08:00
|
|
|
|
{
|
2021-07-11 18:43:25 +08:00
|
|
|
|
#region fields
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// All of the node
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal List<TreeNode<TItem>> _allNodes = new List<TreeNode<TItem>>();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// All the checked nodes
|
|
|
|
|
/// </summary>
|
|
|
|
|
private ConcurrentDictionary<long, TreeNode<TItem>> _checkedNodes = new ConcurrentDictionary<long, TreeNode<TItem>>();
|
|
|
|
|
|
|
|
|
|
#endregion fields
|
|
|
|
|
|
2020-10-09 15:13:32 +08:00
|
|
|
|
#region Tree
|
2020-06-29 15:39:18 +08:00
|
|
|
|
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Shows an expansion icon before the node
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
2020-06-29 15:39:18 +08:00
|
|
|
|
[Parameter]
|
2020-10-09 15:13:32 +08:00
|
|
|
|
public bool ShowExpand { get; set; } = true;
|
2020-06-29 15:39:18 +08:00
|
|
|
|
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Shows a connecting line
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
2020-06-29 15:39:18 +08:00
|
|
|
|
[Parameter]
|
2021-07-11 18:43:25 +08:00
|
|
|
|
public bool ShowLine
|
|
|
|
|
{
|
|
|
|
|
get => _showLine;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_showLine = value;
|
|
|
|
|
if (!_hasSetShowLeafIcon)
|
|
|
|
|
{
|
|
|
|
|
ShowLeafIcon = _showLine;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-29 15:39:18 +08:00
|
|
|
|
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// show treeNode icon icon
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
2020-06-29 15:39:18 +08:00
|
|
|
|
[Parameter]
|
|
|
|
|
public bool ShowIcon { get; set; }
|
|
|
|
|
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Whether treeNode fill remaining horizontal space
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
2020-06-29 15:39:18 +08:00
|
|
|
|
[Parameter]
|
2020-10-09 15:13:32 +08:00
|
|
|
|
public bool BlockNode { get; set; }
|
2020-06-29 15:39:18 +08:00
|
|
|
|
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Whether the node allows drag and drop
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
2020-06-29 15:39:18 +08:00
|
|
|
|
[Parameter]
|
2020-10-09 15:13:32 +08:00
|
|
|
|
public bool Draggable { get; set; }
|
2020-06-29 15:39:18 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// The tree is disabled
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public bool Disabled { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Displays the cotyledon icon
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public bool ShowLeafIcon
|
|
|
|
|
{
|
|
|
|
|
get => _showLeafIcon;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_showLeafIcon = value;
|
|
|
|
|
_hasSetShowLeafIcon = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool _hasSetShowLeafIcon;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Specific the Icon type of switcher
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public string SwitcherIcon { get; set; }
|
|
|
|
|
|
|
|
|
|
public bool Directory { get; set; }
|
|
|
|
|
|
2020-10-09 15:13:32 +08:00
|
|
|
|
private void SetClassMapper()
|
|
|
|
|
{
|
2021-03-12 17:02:11 +08:00
|
|
|
|
ClassMapper
|
|
|
|
|
.Add("ant-tree")
|
2020-10-09 15:13:32 +08:00
|
|
|
|
.If("ant-tree-show-line", () => ShowLine)
|
|
|
|
|
.If("ant-tree-icon-hide", () => ShowIcon)
|
|
|
|
|
.If("ant-tree-block-node", () => BlockNode)
|
2021-07-11 18:43:25 +08:00
|
|
|
|
.If("ant-tree-directory", () => Directory)
|
2021-03-12 17:02:11 +08:00
|
|
|
|
.If("draggable-tree", () => Draggable)
|
2021-07-11 18:43:25 +08:00
|
|
|
|
.If("ant-tree-unselectable", () => !Selectable)
|
2021-03-12 17:02:11 +08:00
|
|
|
|
.If("ant-tree-rtl", () => RTL);
|
2020-10-09 15:13:32 +08:00
|
|
|
|
}
|
2020-06-29 15:39:18 +08:00
|
|
|
|
|
2021-01-07 00:41:26 +08:00
|
|
|
|
#endregion Tree
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
|
|
|
|
#region Node
|
2020-06-29 15:39:18 +08:00
|
|
|
|
|
|
|
|
|
[Parameter]
|
2020-10-09 15:13:32 +08:00
|
|
|
|
public RenderFragment Nodes { get; set; }
|
2020-06-29 15:39:18 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// tree childnodes
|
|
|
|
|
/// Add values when the node is initialized
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal List<TreeNode<TItem>> ChildNodes { get; set; } = new List<TreeNode<TItem>>();
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Add a node
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="treeNode"></param>
|
2020-12-30 18:38:35 +08:00
|
|
|
|
internal void AddNode(TreeNode<TItem> treeNode)
|
2020-10-09 15:13:32 +08:00
|
|
|
|
{
|
2021-07-11 18:43:25 +08:00
|
|
|
|
treeNode.NodeIndex = ChildNodes.Count;
|
2020-10-09 15:13:32 +08:00
|
|
|
|
ChildNodes.Add(treeNode);
|
|
|
|
|
}
|
2020-06-29 15:39:18 +08:00
|
|
|
|
|
2021-01-07 00:41:26 +08:00
|
|
|
|
#endregion Node
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
|
|
|
|
#region Selected
|
2020-06-29 15:39:18 +08:00
|
|
|
|
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Whether can be selected
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public bool Selectable { get; set; } = true;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Allows selecting multiple treeNodes
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
2020-06-29 15:39:18 +08:00
|
|
|
|
[Parameter]
|
2020-10-09 15:13:32 +08:00
|
|
|
|
public bool Multiple { get; set; }
|
2020-06-29 15:39:18 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
[Parameter]
|
|
|
|
|
public string[] DefaultSelectedKeys { get; set; }
|
|
|
|
|
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// The selected tree node
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
2020-12-30 18:38:35 +08:00
|
|
|
|
internal Dictionary<long, TreeNode<TItem>> SelectedNodesDictionary { get; set; } = new Dictionary<long, TreeNode<TItem>>();
|
2020-06-29 15:39:18 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
internal List<string> SelectedTitles => SelectedNodesDictionary.Select(x => x.Value.Title).ToList();
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Add the selected node
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="treeNode"></param>
|
2020-12-30 18:38:35 +08:00
|
|
|
|
internal void SelectedNodeAdd(TreeNode<TItem> treeNode)
|
2020-06-29 15:39:18 +08:00
|
|
|
|
{
|
2020-12-30 18:38:35 +08:00
|
|
|
|
if (SelectedNodesDictionary.ContainsKey(treeNode.NodeId) == false)
|
|
|
|
|
SelectedNodesDictionary.Add(treeNode.NodeId, treeNode);
|
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
if (OnSelect.HasDelegate)
|
|
|
|
|
{
|
|
|
|
|
OnSelect.InvokeAsync(new TreeEventArgs<TItem>(this, treeNode));
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-30 18:38:35 +08:00
|
|
|
|
UpdateBindData();
|
2020-06-29 15:39:18 +08:00
|
|
|
|
}
|
2020-12-30 18:38:35 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// remove the selected node
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="treeNode"></param>
|
2020-12-30 18:38:35 +08:00
|
|
|
|
internal void SelectedNodeRemove(TreeNode<TItem> treeNode)
|
2020-06-29 15:39:18 +08:00
|
|
|
|
{
|
2020-12-30 18:38:35 +08:00
|
|
|
|
if (SelectedNodesDictionary.ContainsKey(treeNode.NodeId) == true)
|
|
|
|
|
SelectedNodesDictionary.Remove(treeNode.NodeId);
|
|
|
|
|
|
|
|
|
|
UpdateBindData();
|
2020-06-29 15:39:18 +08:00
|
|
|
|
}
|
2020-12-30 18:38:35 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Deselect all selections
|
|
|
|
|
/// </summary>
|
2020-10-09 15:13:32 +08:00
|
|
|
|
public void DeselectAll()
|
2020-06-29 15:39:18 +08:00
|
|
|
|
{
|
2020-10-09 15:13:32 +08:00
|
|
|
|
foreach (var item in SelectedNodesDictionary.Select(x => x.Value).ToList())
|
2020-06-29 15:39:18 +08:00
|
|
|
|
{
|
2020-10-09 15:13:32 +08:00
|
|
|
|
item.SetSelected(false);
|
2020-06-29 15:39:18 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-29 23:24:21 +08:00
|
|
|
|
|
2020-12-30 18:38:35 +08:00
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// @bind-SelectedKey
|
2020-12-30 18:38:35 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public string SelectedKey { get; set; }
|
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
///
|
|
|
|
|
/// </summary>
|
2020-12-30 18:38:35 +08:00
|
|
|
|
[Parameter]
|
|
|
|
|
public EventCallback<string> SelectedKeyChanged { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// @bind-SelectedNode
|
2020-12-30 18:38:35 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public TreeNode<TItem> SelectedNode { get; set; }
|
|
|
|
|
|
|
|
|
|
[Parameter]
|
|
|
|
|
public EventCallback<TreeNode<TItem>> SelectedNodeChanged { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// @bing-SelectedData
|
2020-12-30 18:38:35 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public TItem SelectedData { get; set; }
|
|
|
|
|
|
|
|
|
|
[Parameter]
|
|
|
|
|
public EventCallback<TItem> SelectedDataChanged { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
///
|
2020-12-30 18:38:35 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public string[] SelectedKeys { get; set; }
|
|
|
|
|
|
|
|
|
|
[Parameter]
|
|
|
|
|
public EventCallback<string[]> SelectedKeysChanged { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// The collection of selected nodes
|
2020-12-30 18:38:35 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public TreeNode<TItem>[] SelectedNodes { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// The selected data set
|
2020-12-30 18:38:35 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public TItem[] SelectedDatas { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Update binding data
|
2020-12-30 18:38:35 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
private void UpdateBindData()
|
|
|
|
|
{
|
|
|
|
|
if (SelectedNodesDictionary.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
SelectedKey = null;
|
|
|
|
|
SelectedNode = null;
|
|
|
|
|
SelectedData = default(TItem);
|
|
|
|
|
SelectedKeys = Array.Empty<string>();
|
|
|
|
|
SelectedNodes = Array.Empty<TreeNode<TItem>>();
|
|
|
|
|
SelectedDatas = Array.Empty<TItem>();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var selectedFirst = SelectedNodesDictionary.FirstOrDefault();
|
|
|
|
|
SelectedKey = selectedFirst.Value?.Key;
|
|
|
|
|
SelectedNode = selectedFirst.Value;
|
|
|
|
|
SelectedData = selectedFirst.Value.DataItem;
|
|
|
|
|
SelectedKeys = SelectedNodesDictionary.Select(x => x.Value.Key).ToArray();
|
|
|
|
|
SelectedNodes = SelectedNodesDictionary.Select(x => x.Value).ToArray();
|
|
|
|
|
SelectedDatas = SelectedNodesDictionary.Select(x => x.Value.DataItem).ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SelectedKeyChanged.HasDelegate) SelectedKeyChanged.InvokeAsync(SelectedKey);
|
|
|
|
|
if (SelectedNodeChanged.HasDelegate) SelectedNodeChanged.InvokeAsync(SelectedNode);
|
|
|
|
|
if (SelectedDataChanged.HasDelegate) SelectedDataChanged.InvokeAsync(SelectedData);
|
|
|
|
|
if (SelectedKeysChanged.HasDelegate) SelectedKeysChanged.InvokeAsync(SelectedKeys);
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-07 00:41:26 +08:00
|
|
|
|
#endregion Selected
|
2020-06-29 23:24:21 +08:00
|
|
|
|
|
2020-10-09 15:13:32 +08:00
|
|
|
|
#region Checkable
|
2020-06-29 23:24:21 +08:00
|
|
|
|
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Add a Checkbox before the node
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public bool Checkable { get; set; }
|
2020-06-29 23:24:21 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Check treeNode precisely; parent treeNode and children treeNodes are not associated
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public bool CheckStrictly { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Checked keys
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public string[] CheckedKeys { get; set; } = Array.Empty<string>();
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// @bind-CheckedKeys
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public EventCallback<string[]> CheckedKeysChanged { get; set; }
|
2020-06-29 23:24:21 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Dechecked all selected items
|
|
|
|
|
/// </summary>
|
2021-07-09 17:16:35 +08:00
|
|
|
|
public void CheckedAll()
|
|
|
|
|
{
|
|
|
|
|
foreach (var item in ChildNodes)
|
|
|
|
|
{
|
|
|
|
|
item.SetChecked(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
// Decheck all of the checked nodes
|
2020-10-09 15:13:32 +08:00
|
|
|
|
public void DecheckedAll()
|
2020-06-29 23:24:21 +08:00
|
|
|
|
{
|
2020-10-09 15:13:32 +08:00
|
|
|
|
foreach (var item in ChildNodes)
|
|
|
|
|
{
|
|
|
|
|
item.SetChecked(false);
|
|
|
|
|
}
|
2020-06-29 23:24:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Specifies the keys of the default checked treeNodes
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public string[] DefaultCheckedKeys { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Disable node Checkbox
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string[] DisableCheckKeys { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Adds or removes a checkbox node
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="treeNode"></param>
|
|
|
|
|
internal void AddOrRemoveCheckNode(TreeNode<TItem> treeNode)
|
|
|
|
|
{
|
|
|
|
|
if (treeNode.Checked)
|
|
|
|
|
_checkedNodes.TryAdd(treeNode.NodeId, treeNode);
|
|
|
|
|
else
|
|
|
|
|
_checkedNodes.TryRemove(treeNode.NodeId, out TreeNode<TItem> _);
|
|
|
|
|
CheckedKeys = _checkedNodes.Select(x => x.Value.Key).ToArray();
|
|
|
|
|
if (CheckedKeysChanged.HasDelegate) CheckedKeysChanged.InvokeAsync(CheckedKeys);
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-07 00:41:26 +08:00
|
|
|
|
#endregion Checkable
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
|
|
|
|
#region Search
|
2020-06-29 23:24:21 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
private string _searchValue;
|
|
|
|
|
private bool _showLeafIcon;
|
|
|
|
|
private bool _showLine;
|
2021-01-07 00:41:26 +08:00
|
|
|
|
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// search value
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public string SearchValue
|
|
|
|
|
{
|
|
|
|
|
get => _searchValue;
|
|
|
|
|
set
|
2020-06-29 23:24:21 +08:00
|
|
|
|
{
|
2020-10-09 15:13:32 +08:00
|
|
|
|
_searchValue = value;
|
2021-07-11 18:43:25 +08:00
|
|
|
|
var allList = _allNodes.ToList();
|
|
|
|
|
List<TreeNode<TItem>> searchDatas = null, exceptList = null;
|
|
|
|
|
if (!String.IsNullOrEmpty(value))
|
|
|
|
|
searchDatas = allList.Where(x => x.Title.Contains(value)).ToList();
|
|
|
|
|
if (searchDatas != null && searchDatas.Any())
|
|
|
|
|
exceptList = allList.Except(searchDatas).ToList();
|
|
|
|
|
if (exceptList != null || searchDatas != null)
|
|
|
|
|
{
|
|
|
|
|
exceptList?.ForEach(m => { m.Expand(false); m.Matched = false; });
|
|
|
|
|
searchDatas?.ForEach(node => { node.OpenPropagation(); node.Matched = true; });
|
|
|
|
|
}
|
|
|
|
|
else
|
2020-06-29 23:24:21 +08:00
|
|
|
|
{
|
2021-07-11 18:43:25 +08:00
|
|
|
|
allList.ForEach(m => { m.Matched = false; });
|
2020-06-29 23:24:21 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
///// <summary>
|
|
|
|
|
/////
|
|
|
|
|
///// </summary>
|
|
|
|
|
//[Parameter]
|
|
|
|
|
//public EventCallback<TreeEventArgs<TItem>> OnSearchValueChanged { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Search for matching text styles
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
[Parameter]
|
|
|
|
|
public string MatchedStyle { get; set; } = "";
|
2020-06-29 23:24:21 +08:00
|
|
|
|
|
2021-01-07 00:41:26 +08:00
|
|
|
|
#endregion Search
|
2020-06-29 23:24:21 +08:00
|
|
|
|
|
2020-10-09 15:13:32 +08:00
|
|
|
|
#region DataBind
|
2020-06-29 23:24:21 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
///
|
|
|
|
|
/// </summary>
|
2020-10-09 15:13:32 +08:00
|
|
|
|
[Parameter]
|
2021-07-11 18:43:25 +08:00
|
|
|
|
public IEnumerable<TItem> DataSource { get; set; }
|
2020-06-29 23:24:21 +08:00
|
|
|
|
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Specifies a method that returns the text of the node.
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
2020-12-30 18:38:35 +08:00
|
|
|
|
public Func<TreeNode<TItem>, string> TitleExpression { get; set; }
|
2020-06-29 23:24:21 +08:00
|
|
|
|
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Specifies a method that returns the key of the node.
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
2020-12-30 18:38:35 +08:00
|
|
|
|
public Func<TreeNode<TItem>, string> KeyExpression { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Specifies a method to return the node icon.
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
2020-12-30 18:38:35 +08:00
|
|
|
|
public Func<TreeNode<TItem>, string> IconExpression { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Specifies a method that returns whether the expression is a leaf node.
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
2020-12-30 18:38:35 +08:00
|
|
|
|
public Func<TreeNode<TItem>, bool> IsLeafExpression { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Specifies a method to return a child node
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
2020-12-30 18:38:35 +08:00
|
|
|
|
public Func<TreeNode<TItem>, IList<TItem>> ChildrenExpression { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Specifies a method to return a disabled node
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public Func<TreeNode<TItem>, bool> DisabledExpression { get; set; }
|
|
|
|
|
|
2021-01-07 00:41:26 +08:00
|
|
|
|
#endregion DataBind
|
2020-06-29 23:24:21 +08:00
|
|
|
|
|
2020-10-09 15:13:32 +08:00
|
|
|
|
#region Event
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Lazy load callbacks
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <remarks>You must use async and the return type is Task, otherwise you may experience load lag and display problems</remarks>
|
2020-10-09 15:13:32 +08:00
|
|
|
|
[Parameter]
|
2020-12-30 18:38:35 +08:00
|
|
|
|
public EventCallback<TreeEventArgs<TItem>> OnNodeLoadDelayAsync { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Click the tree node callback
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
2020-12-30 18:38:35 +08:00
|
|
|
|
public EventCallback<TreeEventArgs<TItem>> OnClick { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Double-click the node callback
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
2020-12-30 18:38:35 +08:00
|
|
|
|
public EventCallback<TreeEventArgs<TItem>> OnDblClick { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Right-click tree node callback
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
2020-12-30 18:38:35 +08:00
|
|
|
|
public EventCallback<TreeEventArgs<TItem>> OnContextMenu { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// checked the tree node callback
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
2021-07-11 18:43:25 +08:00
|
|
|
|
public EventCallback<TreeEventArgs<TItem>> OnCheck { get; set; }
|
|
|
|
|
|
|
|
|
|
[Parameter]
|
|
|
|
|
public EventCallback<TreeEventArgs<TItem>> OnSelect { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Click the expansion tree node icon to call back
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
2020-12-30 18:38:35 +08:00
|
|
|
|
public EventCallback<TreeEventArgs<TItem>> OnExpandChanged { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
#endregion Event
|
|
|
|
|
|
|
|
|
|
#region Template
|
|
|
|
|
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// The indentation template
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
2021-07-11 18:43:25 +08:00
|
|
|
|
public RenderFragment<TreeNode<TItem>> IndentTemplate { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Customize the header template
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public RenderFragment<TreeNode<TItem>> TitleTemplate { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Customize the icon templates
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public RenderFragment<TreeNode<TItem>> TitleIconTemplate { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Customize toggle icon templates
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public RenderFragment<TreeNode<TItem>> SwitcherIconTemplate { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
#endregion Template
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
#region DragDrop
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当前拖拽项
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal TreeNode<TItem> DragItem { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Called when the drag and drop begins
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public EventCallback<TreeEventArgs<TItem>> OnDragStart { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Called when drag and drop into a releasable target
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
2021-07-11 18:43:25 +08:00
|
|
|
|
public EventCallback<TreeEventArgs<TItem>> OnDragEnter { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Called when drag and drop away from a releasable target
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
2021-07-11 18:43:25 +08:00
|
|
|
|
public EventCallback<TreeEventArgs<TItem>> OnDragLeave { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Triggered when drag-and-drop drops succeed
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
2021-07-11 18:43:25 +08:00
|
|
|
|
public EventCallback<TreeEventArgs<TItem>> OnDrop { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Drag-and-drop end callback
|
2020-10-09 15:13:32 +08:00
|
|
|
|
/// </summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <remarks>this callback method must be set</remarks>
|
2020-10-09 15:13:32 +08:00
|
|
|
|
[Parameter]
|
2021-07-11 18:43:25 +08:00
|
|
|
|
public EventCallback<TreeEventArgs<TItem>> OnDragEnd { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
#endregion DragDrop
|
2021-01-07 00:41:26 +08:00
|
|
|
|
|
|
|
|
|
protected override void OnInitialized()
|
|
|
|
|
{
|
|
|
|
|
SetClassMapper();
|
|
|
|
|
base.OnInitialized();
|
|
|
|
|
}
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
2020-10-21 13:51:41 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Find Node
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="predicate">Predicate</param>
|
|
|
|
|
/// <param name="recursive">Recursive Find</param>
|
|
|
|
|
/// <returns></returns>
|
2020-12-30 18:38:35 +08:00
|
|
|
|
public TreeNode<TItem> FindFirstOrDefaultNode(Func<TreeNode<TItem>, bool> predicate, bool recursive = true)
|
2020-10-21 13:51:41 +08:00
|
|
|
|
{
|
|
|
|
|
foreach (var child in ChildNodes)
|
|
|
|
|
{
|
2021-01-07 00:41:26 +08:00
|
|
|
|
if (predicate != null && predicate.Invoke(child))
|
2020-10-21 13:51:41 +08:00
|
|
|
|
{
|
|
|
|
|
return child;
|
|
|
|
|
}
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
2020-10-21 13:51:41 +08:00
|
|
|
|
if (recursive)
|
|
|
|
|
{
|
|
|
|
|
var find = child.FindFirstOrDefaultNode(predicate, recursive);
|
|
|
|
|
if (find != null)
|
|
|
|
|
{
|
|
|
|
|
return find;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2021-01-07 00:41:26 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
#region Expand
|
|
|
|
|
|
2020-10-21 13:51:41 +08:00
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// All tree nodes are expanded by default
|
2020-10-21 13:51:41 +08:00
|
|
|
|
/// </summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
[Parameter]
|
|
|
|
|
public bool DefaultExpandAll { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The parent node is expanded by default
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public bool DefaultExpandParent { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Expand the specified tree node by default
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public string[] DefaultExpandedKeys { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// (Controlled) expands the specified tree node
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public string[] ExpandedKeys { get; set; }
|
|
|
|
|
|
|
|
|
|
[Parameter]
|
|
|
|
|
public EventCallback<string[]> ExpandedKeysChanged { get; set; }
|
|
|
|
|
|
|
|
|
|
[Parameter]
|
|
|
|
|
public EventCallback<(string[] ExpandedKeys, TreeNode<TItem> Node, bool Expanded)> OnExpand { get; set; }
|
|
|
|
|
|
|
|
|
|
[Parameter]
|
|
|
|
|
public bool AutoExpandParent { get; set; }
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
2021-01-07 00:41:26 +08:00
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Expand all nodes
|
2021-01-07 00:41:26 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
public void ExpandAll()
|
|
|
|
|
{
|
|
|
|
|
this.ChildNodes.ForEach(node => Switch(node, true));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// Collapse all nodes
|
2021-01-07 00:41:26 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
public void CollapseAll()
|
|
|
|
|
{
|
|
|
|
|
this.ChildNodes.ForEach(node => Switch(node, false));
|
|
|
|
|
}
|
2020-10-09 15:13:32 +08:00
|
|
|
|
|
2021-07-11 18:43:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 节点展开关闭
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="node"></param>
|
|
|
|
|
/// <param name="expanded"></param>
|
2021-01-07 00:41:26 +08:00
|
|
|
|
private void Switch(TreeNode<TItem> node, bool expanded)
|
2020-10-09 15:13:32 +08:00
|
|
|
|
{
|
2021-01-07 00:41:26 +08:00
|
|
|
|
node.Expand(expanded);
|
|
|
|
|
node.ChildNodes.ForEach(n => Switch(n, expanded));
|
2020-10-09 15:13:32 +08:00
|
|
|
|
}
|
2021-07-11 18:43:25 +08:00
|
|
|
|
|
|
|
|
|
internal async Task OnNodeExpand(TreeNode<TItem> node, bool expanded, MouseEventArgs args)
|
|
|
|
|
{
|
|
|
|
|
var expandedKeys = _allNodes.Select(x => x.Key).ToArray();
|
|
|
|
|
if (OnNodeLoadDelayAsync.HasDelegate && expanded == true)
|
|
|
|
|
{
|
|
|
|
|
node.SetLoading(true);
|
|
|
|
|
await OnNodeLoadDelayAsync.InvokeAsync(new TreeEventArgs<TItem>(this, node, args));
|
|
|
|
|
node.SetLoading(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (OnExpandChanged.HasDelegate)
|
|
|
|
|
{
|
|
|
|
|
await OnExpandChanged.InvokeAsync(new TreeEventArgs<TItem>(this, node, args));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ExpandedKeysChanged.HasDelegate)
|
|
|
|
|
{
|
|
|
|
|
await ExpandedKeysChanged.InvokeAsync(expandedKeys);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (OnExpand.HasDelegate)
|
|
|
|
|
{
|
|
|
|
|
await OnExpand.InvokeAsync((expandedKeys, node, expanded));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (AutoExpandParent && expanded)
|
|
|
|
|
{
|
|
|
|
|
node.ParentNode?.Expand(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion Expand
|
2020-06-29 15:39:18 +08:00
|
|
|
|
}
|
|
|
|
|
}
|