perf(adminui): RawTree renders a flat Virtualize list, pages 500 per level, caches menus (R04 P5)
The recursive RenderNode rendered every row of an expanded device, and built a fresh context-menu list + closures per node per render. RawTreeRows flattens the expanded tree (explicit stack) into rows rendered by one Virtualize; each level shows 500 children, then a 'Show more' row. RawNodeMenuCache keys menus weakly on the node instance and rebuilds on a picker-mode or Enabled change. Refs #745 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Uns;
|
||||
|
||||
/// <summary>
|
||||
/// Caches each <see cref="RawNode"/>'s context-menu item list (R04 P5). <c>RawTree</c> used to build a
|
||||
/// fresh list (and fresh closures) per node on every render, and hand it to that row's
|
||||
/// <c>ContextMenu</c> as a new reference each time. The cache is keyed weakly on the node instance, so
|
||||
/// a reload (which replaces the child nodes) drops the stale entries with the nodes, and it rebuilds
|
||||
/// when anything the menu depends on (picker mode, the node's enabled state) differs.
|
||||
/// </summary>
|
||||
public sealed class RawNodeMenuCache
|
||||
{
|
||||
private readonly ConditionalWeakTable<RawNode, Entry> _entries = new();
|
||||
|
||||
/// <summary>Returns the cached menu for <paramref name="node"/>, building it on first use or after a dependency changed.</summary>
|
||||
/// <param name="node">The node.</param>
|
||||
/// <param name="pickerMode">Whether the tree is in picker mode (picker menus differ entirely).</param>
|
||||
/// <param name="build">Builds the menu for the node.</param>
|
||||
/// <returns>The menu items.</returns>
|
||||
public IReadOnlyList<ContextMenuItem> GetOrBuild(
|
||||
RawNode node, bool pickerMode, Func<RawNode, IReadOnlyList<ContextMenuItem>> build)
|
||||
{
|
||||
if (_entries.TryGetValue(node, out var entry)
|
||||
&& entry.PickerMode == pickerMode
|
||||
&& entry.Enabled == node.Enabled)
|
||||
{
|
||||
return entry.Items;
|
||||
}
|
||||
|
||||
var items = build(node);
|
||||
_entries.AddOrUpdate(node, new Entry(pickerMode, node.Enabled, items));
|
||||
return items;
|
||||
}
|
||||
|
||||
private sealed record Entry(bool PickerMode, bool Enabled, IReadOnlyList<ContextMenuItem> Items);
|
||||
}
|
||||
Reference in New Issue
Block a user