Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/Components/Table/Table.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,7 @@ protected override void OnInitialized()
base.OnInitialized();

// 初始化节点缓存
TreeNodeCache ??= new(Equals);
TreeNodeCache ??= new(this);
OnInitLocalization();

// 设置 OnSort 回调方法
Expand Down
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ protected override void OnInitialized()
base.OnInitialized();

// 初始化节点缓存
TreeNodeStateCache ??= new(Equals);
TreeNodeStateCache ??= new(this);
NotSetOnTreeExpandErrorMessage = Localizer[nameof(NotSetOnTreeExpandErrorMessage)];
}

Expand Down
58 changes: 28 additions & 30 deletions src/BootstrapBlazor/Misc/ExpandableNodeCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,32 @@ namespace BootstrapBlazor.Components;
/// </summary>
/// <typeparam name="TNode"></typeparam>
/// <typeparam name="TItem"></typeparam>
/// <remarks>
/// 构造函数
/// </remarks>
public class ExpandableNodeCache<TNode, TItem>(Func<TItem, TItem, bool> comparer) where TNode : IExpandableNode<TItem>
public class ExpandableNodeCache<TNode, TItem> where TNode : IExpandableNode<TItem>
{
/// <summary>
/// 所有已展开行集合 作为缓存使用
/// </summary>
protected List<TItem> ExpandedNodeCache { get; } = new(50);
protected HashSet<TItem> ExpandedNodeCache { get; }

/// <summary>
/// 所有已收缩行集合 作为缓存使用
/// </summary>
protected List<TItem> CollapsedNodeCache { get; } = new(50);
protected HashSet<TItem> CollapsedNodeCache { get; }

/// <summary>
/// 对象比较器
/// </summary>
protected IEqualityComparer<TItem> EqualityComparer { get; } = new ModelComparer<TItem>(comparer);
protected IEqualityComparer<TItem> EqualityComparer { get; }

/// <remarks>
/// 构造函数
/// </remarks>
public ExpandableNodeCache(IModelEqualityComparer<TItem> comparer)
{
EqualityComparer = new HashSetComparer<TItem>(comparer);
ExpandedNodeCache = new(50, EqualityComparer);
CollapsedNodeCache = new(50, EqualityComparer);
}
/// <summary>
/// 节点展开收缩状态切换方法
/// </summary>
Expand All @@ -42,13 +48,10 @@ public virtual async Task ToggleNodeAsync(TNode node, Func<TNode, Task<IEnumerab
if (node.IsExpand)
{
// 展开节点缓存增加此节点
if (!ExpandedNodeCache.Any(i => EqualityComparer.Equals(i, node.Value)))
{
ExpandedNodeCache.Add(node.Value);
}
ExpandedNodeCache.Add(node.Value);

// 收缩节点缓存移除此节点
CollapsedNodeCache.RemoveAll(i => EqualityComparer.Equals(i, node.Value));
CollapsedNodeCache.Remove(node.Value);

// 无子项时通过回调方法延时加载
if (!node.Items.Any())
Expand All @@ -64,13 +67,10 @@ public virtual async Task ToggleNodeAsync(TNode node, Func<TNode, Task<IEnumerab
else
{
// 展开节点缓存移除此节点
ExpandedNodeCache.RemoveAll(i => EqualityComparer.Equals(i, node.Value));
ExpandedNodeCache.Remove(node.Value);

// 收缩节点缓存添加此节点
if (!CollapsedNodeCache.Any(i => EqualityComparer.Equals(i, node.Value)))
{
CollapsedNodeCache.Add(node.Value);
}
CollapsedNodeCache.Add(node.Value);
}
}

Expand All @@ -85,20 +85,18 @@ public async Task CheckExpandAsync(TNode node, Func<TNode, Task<IEnumerable<IExp
if (node.IsExpand)
{
// 已收缩
if (CollapsedNodeCache.Contains(node.Value, EqualityComparer))
if (CollapsedNodeCache.Contains(node.Value))
{
node.IsExpand = false;
}
else if (!ExpandedNodeCache.Contains(node.Value, EqualityComparer))
{
// 状态为 展开
ExpandedNodeCache.Add(node.Value);
}

// 状态为 展开
ExpandedNodeCache.Add(node.Value);
}
else
{
var needRemove = true;
if (ExpandedNodeCache.Any(i => EqualityComparer.Equals(i, node.Value)))
if (ExpandedNodeCache.Contains(node.Value))
{
// 原来是展开状态,
if (node.HasChildren)
Expand All @@ -119,7 +117,7 @@ public async Task CheckExpandAsync(TNode node, Func<TNode, Task<IEnumerable<IExp
}
if (needRemove)
{
ExpandedNodeCache.RemoveAll(i => EqualityComparer.Equals(i, node.Value));
ExpandedNodeCache.Remove(node.Value);
}
}
}
Expand All @@ -132,7 +130,7 @@ public async Task CheckExpandAsync(TNode node, Func<TNode, Task<IEnumerable<IExp
/// <param name="ret">查询结果 查无资料时为 null</param>
/// <returns>是否存在 <paramref name="target"/></returns>
/// <remarks>采广度优先搜寻</remarks>
public bool TryFind(IEnumerable<TNode> items, TItem target, [MaybeNullWhen(false)] out TNode ret)
public bool TryFind(List<TNode> items, TItem target, [MaybeNullWhen(false)] out TNode ret)
{
ret = Find(items, target);
return ret != null;
Expand All @@ -145,7 +143,7 @@ public bool TryFind(IEnumerable<TNode> items, TItem target, [MaybeNullWhen(false
/// <param name="target"></param>
/// <returns>查询结果 查无资料时为 null</returns>
/// <remarks>采广度优先搜寻</remarks>
private TNode? Find(IEnumerable<TNode> items, TItem target) => Find(items, target, out _);
private TNode? Find(List<TNode> items, TItem target) => Find(items, target, out _);

/// <summary>
/// 在全部树状结构 <paramref name="source"/> 中寻找指定 <paramref name="target"/>
Expand All @@ -155,14 +153,14 @@ public bool TryFind(IEnumerable<TNode> items, TItem target, [MaybeNullWhen(false
/// <param name="degree">树状阶层,起始为0</param>
/// <returns>查询结果 查无资料时为 null</returns>
/// <remarks>采广度优先搜寻</remarks>
public TNode? Find(IEnumerable<TNode> source, TItem target, out int degree)
public TNode? Find(List<TNode> source, TItem target, out int degree)
{
degree = -1;
var ret = source.FirstOrDefault(item => EqualityComparer.Equals(item.Value, target));
if (ret == null)
{
var children = source.SelectMany(e => e.Items.OfType<TNode>());
if (children.Any())
var children = source.SelectMany(e => e.Items.OfType<TNode>()).ToList();
if (children.Count != 0)
{
ret = Find(children, target, out degree);
}
Expand Down
32 changes: 32 additions & 0 deletions src/BootstrapBlazor/Misc/HashSetComparer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the Apache 2.0 License
// See the LICENSE file in the project root for more information.
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone

namespace BootstrapBlazor.Components;

/// <summary>
/// 模型比较器
/// </summary>
/// <typeparam name="TItem"></typeparam>
public class HashSetComparer<TItem>(IModelEqualityComparer<TItem> comparer) : IEqualityComparer<TItem>
{
/// <summary>
/// Equals 方法
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public bool Equals(TItem? x, TItem? y) => comparer.Equals(x, y);

/// <summary>
/// GetHashCode 方法
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public int GetHashCode([DisallowNull] TItem obj)
{
var keyValue = Utility.GetKeyValue<TItem, object>(obj, comparer.CustomKeyAttribute);
return keyValue?.GetHashCode() ?? obj.GetHashCode();
}
}
13 changes: 2 additions & 11 deletions src/BootstrapBlazor/Misc/ModelComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,8 @@ namespace BootstrapBlazor.Components;
/// 模型比较器
/// </summary>
/// <typeparam name="TItem"></typeparam>
public class ModelComparer<TItem> : IEqualityComparer<TItem>
public class ModelComparer<TItem>(Func<TItem, TItem, bool> comparer) : IEqualityComparer<TItem>
{
private readonly Func<TItem, TItem, bool> _comparer;
/// <summary>
/// 构造函数
/// </summary>
public ModelComparer(Func<TItem, TItem, bool> comparer)
{
_comparer = comparer;
}

/// <summary>
/// Equals 方法
/// </summary>
Expand All @@ -32,7 +23,7 @@ public bool Equals(TItem? x, TItem? y)
if (x != null && y != null)
{
// 均不为空时走 comparer 方法判断
ret = _comparer(x, y);
ret = comparer(x, y);
}
else
{
Expand Down
Loading