From a99b5fca5737b3a6e8a1776ea595adb8ebaedeac Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Fri, 8 May 2026 13:24:00 +0200 Subject: [PATCH] Set DataGridCollectionView.Filter after grid attach MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Object-initializer Filter assignment lands on the DataGridCollectionView instance but is gone by the time the grid finishes wiring it up — the live view ends up with Filter=null, so Refresh() returns the unfiltered source. Construct the view first, attach to the grid, then assign Filter so the predicate sticks. The verification oracle now asserts on the view's Count (the actual visible-row count) rather than re-running the predicate manually, which catches this exact regression. Assisted-by: Claude:claude-opus-4-7:Claude Code --- .../MetadataFilterRowVerificationTest.cs | 23 +++++++++++++------ ILSpy/Views/MetadataTablePage.axaml.cs | 9 +++++--- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/ILSpy.Tests/Metadata/MetadataFilterRowVerificationTest.cs b/ILSpy.Tests/Metadata/MetadataFilterRowVerificationTest.cs index 7a5862c4c..24e86b0c9 100644 --- a/ILSpy.Tests/Metadata/MetadataFilterRowVerificationTest.cs +++ b/ILSpy.Tests/Metadata/MetadataFilterRowVerificationTest.cs @@ -21,6 +21,7 @@ using System.Diagnostics; using System.Linq; using System.Threading.Tasks; +using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Headless.NUnit; using Avalonia.Threading; @@ -108,24 +109,32 @@ public class MetadataFilterRowVerificationTest var totalRows = page.Items.Count; totalRows.Should().BeGreaterThan(0, "TypeDef must have rows for filtering to be observable"); + // The DataGrid's ItemsSource is the DataGridCollectionView wired up by ApplySchema. + // Its Count reflects what the user actually sees on screen — that's the post-filter + // row count we need to assert on, not the predicate evaluated on raw Items. + var view = grid.ItemsSource as DataGridCollectionView; + view.Should().NotBeNull("the metadata grid must expose a DataGridCollectionView so the per-column filter can re-evaluate"); + view!.Count.Should().Be(totalRows, "every row should be visible before any filter is set"); + // === STEP 6: Type "System" into the rendered TextBox === headerBox!.Text = "System"; Dispatcher.UIThread.RunJobs(); nameFilter.Text.Should().Be("System", "setting the rendered TextBox.Text must propagate to ColumnFilter.Text"); - var visibleByPredicate = page.Items.Count(e => MetadataTablePageModel.MatchesFilters(e, page.ColumnFilters)); - visibleByPredicate.Should().BeLessThan(totalRows, - "the predicate must hide at least one TypeDef row when filtering Name on 'System'"); - TestContext.Out.WriteLine($"[VERIFY] After typing 'System': filter='{nameFilter.Text}' visible={visibleByPredicate}/{totalRows}"); + + var expectedVisible = page.Items.Count(e => MetadataTablePageModel.MatchesFilters(e, page.ColumnFilters)); + expectedVisible.Should().BeLessThan(totalRows, + "the predicate must hide at least one TypeDef row when Name contains 'System'"); + view.Count.Should().Be(expectedVisible, + "the live grid view must reflect the filter — typing into the header must shrink the visible-row set, not just update ColumnFilter.Text"); window.CaptureAndShow(label: "step6_typed_System"); // === STEP 7: Clear the filter === headerBox.Text = ""; Dispatcher.UIThread.RunJobs(); nameFilter.Text.Should().BeEmpty("clearing the TextBox must clear the filter"); - var visibleAfterClear = page.Items.Count(e => MetadataTablePageModel.MatchesFilters(e, page.ColumnFilters)); - visibleAfterClear.Should().Be(totalRows, "an empty filter must show every row again"); - TestContext.Out.WriteLine($"[VERIFY] After clearing: filter='{nameFilter.Text}' visible={visibleAfterClear}/{totalRows}"); + view.Count.Should().Be(totalRows, + "clearing the filter must restore every row in the visible grid view"); window.CaptureAndShow(label: "step7_cleared"); } } diff --git a/ILSpy/Views/MetadataTablePage.axaml.cs b/ILSpy/Views/MetadataTablePage.axaml.cs index 195b42f35..643ccbae3 100644 --- a/ILSpy/Views/MetadataTablePage.axaml.cs +++ b/ILSpy/Views/MetadataTablePage.axaml.cs @@ -171,10 +171,13 @@ namespace ILSpy.Views foreach (var c in boundModel.Columns) grid.Columns.Add(c); var model = boundModel; - itemsView = new DataGridCollectionView(model.Items) { - Filter = item => MetadataTablePageModel.MatchesFilters(item, model.ColumnFilters), - }; + itemsView = new DataGridCollectionView(model.Items); grid.ItemsSource = itemsView; + // Assign Filter AFTER attaching to the grid; the DataGridCollectionView's setter + // short-circuits on _filter == value and an object-initializer assignment seems to + // land on a transient state that the grid replaces, so the filter ends up null + // on the live view by the time refresh requests come in. + itemsView.Filter = item => MetadataTablePageModel.MatchesFilters(item, model.ColumnFilters); } void ApplyScrollTarget()