From d164a99ed970eebb6b592ec362f60d33ada332d1 Mon Sep 17 00:00:00 2001 From: Loretta Date: Fri, 17 Jul 2026 05:51:31 +0200 Subject: [PATCH] Fix: TagBox reloads on in-place Data refill Improved MgGridFilterPanelTagBox to detect in-place Data collection refills and trigger DevExpress editor Reload(), ensuring tags resolve when the collection is updated without changing its reference. Updated MGGRID_PARAMETERS.md to document this behavior and clarify why Reload() is needed for in-place fills. --- .../Components/Grids/MgGridFilterPanelTagBox.cs | 7 +++++++ AyCode.Blazor.Components/docs/MGGRID/MGGRID_PARAMETERS.md | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/AyCode.Blazor.Components/Components/Grids/MgGridFilterPanelTagBox.cs b/AyCode.Blazor.Components/Components/Grids/MgGridFilterPanelTagBox.cs index aa40a00..bc8329b 100644 --- a/AyCode.Blazor.Components/Components/Grids/MgGridFilterPanelTagBox.cs +++ b/AyCode.Blazor.Components/Components/Grids/MgGridFilterPanelTagBox.cs @@ -59,6 +59,7 @@ public class MgGridFilterPanelTagBox : MgTagBox, I // fill the SAME instance later (AcObservableCollection.Replace) — the reference never changes, only // the count does (0 => N). Count() is O(1) for ICollection-backed lookups. var dataCount = Data?.Count() ?? -1; + var sameInstanceRefilled = ReferenceEquals(Data, _lastSyncedData) && dataCount != _lastSyncedDataCount; var dataChanged = !ReferenceEquals(Data, _lastSyncedData) || dataCount != _lastSyncedDataCount; var selectionDrifted = Values is null || !Values.SequenceEqual(criteriaValues); @@ -66,6 +67,12 @@ public class MgGridFilterPanelTagBox : MgTagBox, I { _lastSyncedData = Data; _lastSyncedDataCount = dataCount; + + // DevExpress snapshots the editor's item list and detects Data changes BY REFERENCE — an in-place + // fill is invisible to it, so the re-asserted Values could never resolve into tags (re-rendering + // does not help). Reload() (DxListEditorBase) forces the editor to re-read its Data source. + if (sameInstanceRefilled) Reload(); + SetValuesCore(criteriaValues); } } diff --git a/AyCode.Blazor.Components/docs/MGGRID/MGGRID_PARAMETERS.md b/AyCode.Blazor.Components/docs/MGGRID/MGGRID_PARAMETERS.md index 6356207..cd78c76 100644 --- a/AyCode.Blazor.Components/docs/MGGRID/MGGRID_PARAMETERS.md +++ b/AyCode.Blazor.Components/docs/MGGRID/MGGRID_PARAMETERS.md @@ -80,7 +80,7 @@ A nullable FK column (`int?`) behaves the same — rows whose value is `null` ma **Persistence & visibility.** The panel's criteria is part of the grid's persisted layout (`GridPersistentLayout.FilterCriteria` — the AutoSave tier and the server-roamed UserSave tier alike; see `MGGRID_LAYOUT.md`). Components register with the grid (`IMgGridFilterPanelComponent`, weakly held; `MgGridFilterPanelTagBox` does this automatically) and the grid **reconciles** them after layout restore (incl. on another machine), user-layout load, layout reset, and panel toggle: -- panel **visible** → each component re-reads its field's criteria and re-selects (a restored panel filter is visible again); the restore (JS interop) and an async lookup `Data` arrive in arbitrary order — the tag box re-asserts its selection idempotently on every parameter pass while an owned criteria is active, tracking both the `Data` **instance and its item count** (an in-place fill — `AcObservableCollection.Replace` on a pre-created empty collection — is detected too), so tags resolve as soon as both exist; consumers can additionally force a re-run via `IMgGridBase.RefreshFilterPanel()` after a late lookup load; +- panel **visible** → each component re-reads its field's criteria and re-selects (a restored panel filter is visible again); the restore (JS interop) and an async lookup `Data` arrive in arbitrary order — the tag box re-asserts its selection idempotently on every parameter pass while an owned criteria is active, tracking both the `Data` **instance and its item count** (an in-place fill — `AcObservableCollection.Replace` on a pre-created empty collection — is detected too, and triggers the editor's `Reload()`: DevExpress snapshots its item list and detects `Data` changes by reference, so an in-place fill would otherwise never resolve into tags), so tags resolve as soon as both exist; consumers can additionally force a re-run via `IMgGridBase.RefreshFilterPanel()` after a late lookup load; - panel **hidden** (toolbar toggle or `ShowFilterPanel="false"`) → the components' **own** criteria are **cleared** — a panel filter never filters invisibly. Hiding the panel therefore deliberately discards the current selection (filter-row values survive, per Ownership above); - a per-field criteria the component does not own is left untouched — the component just shows no selection.