Skip to content

Commit ebcc37d

Browse files
scottlerchclaude
andauthored
#79 Modern: adopt CornerRadius clip-escape workaround, drop status-bar backplate (#135)
The modern editor's entries ListView hits a WinUI 3 raster clip-escape bug (upstream microsoft-ui-xaml#11225): once content extent passes ~2^21 DIPs the renderer stops clipping bottom-edge rows and they paint over the status bar. The previous mitigation was an opaque backplate behind the status bar (StatusBackplateThreshold/StatusBackplateVisibility + a Border) that merely occluded the strays — cosmetic, and it dropped the true-Mica look on large files. Two responders on the upstream issue proposed a cleaner fix: give the ListView any non-zero CornerRadius, which forces a composition geometry clip on its content and re-establishes the bottom clip. CornerRadius="0.1" is visually indistinguishable from square and actually keeps rows inside the control, so it works with the transparent Mica band and no backplate is needed. - Add CornerRadius="0.1" to EntriesList. - Remove StatusBackplateThreshold, StatusBackplateVisibility, the backplate Border, and the two OnPropertyChanged(nameof(StatusBackplateVisibility)) calls. - Update the surrounding comments. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 60e8dcf commit ebcc37d

2 files changed

Lines changed: 16 additions & 44 deletions

File tree

HostsFileEditor.WinUI/MainWindow.xaml

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -351,9 +351,19 @@
351351
<TextBlock Text="{x:Bind SelectAllBannerText, Mode=OneWay}" TextWrapping="Wrap"
352352
Foreground="{ThemeResource TextOnAccentFillColorPrimaryBrush}"/>
353353
</Border>
354+
<!-- CornerRadius="0.1" is the fix for the WinUI raster clip-escape bug (issue #79,
355+
upstream microsoft-ui-xaml#11225): once the list's content extent passes ~2^21
356+
DIPs the renderer stops clipping bottom-edge rows and they paint past the list
357+
into the status bar below. Giving the ListView any non-zero CornerRadius forces
358+
a composition geometry clip on its content, which re-establishes the bottom clip
359+
and keeps the strays inside the control. 0.1 is visually indistinguishable from
360+
square. This actually clips (unlike the old opaque backplate, which only occluded
361+
the strays), so it works with the transparent Mica band. Remove once the upstream
362+
bug ships fixed in a Windows App SDK. -->
354363
<ListView x:Name="EntriesList"
355364
Grid.Row="1"
356365
Margin="0,8,0,0"
366+
CornerRadius="0.1"
357367
IsEnabled="{x:Bind IsEntriesInteractive, Mode=OneWay}"
358368
PreviewKeyDown="OnEntriesPreviewKeyDown"
359369
SelectionMode="Extended"
@@ -470,23 +480,12 @@
470480
window's Mica backdrop; it sits in its own fixed-height grid row, so no list content is
471481
ever laid out behind it.
472482
473-
The backplate underneath exists because of a WinUI composition bug with enormous
474-
virtualized lists: past roughly 2^20 device-independent pixels of panel extent
475-
(~32K rows here), the renderer stops clipping the list's bottom-edge rows — the last
476-
partially-visible row paints in FULL, plus the next cache row — straight through the
477-
ListView's viewport clip, an explicit ancestor UIElement.Clip,
478-
CanContentRenderOutsideBounds=False, and CacheLength=0 (all verified ineffective;
479-
element bounds via UIA stay correct, so it is a raster-level escape, not layout). The
480-
stray pixels land under this transparent band and show through it. They only ever paint
481-
DOWNWARD past the list (title/command bars stay clean), and opaque content drawn later
482-
in the tree occludes them — so when the list is large enough for the bug to trigger,
483-
an opaque backplate in SolidBackgroundFillColorBase (the exact base color Mica tints,
484-
i.e. "Mica minus the desktop tint") slides in behind the text. Normal-sized files
485-
(≤10K rows, empirically clean with margin: breakage sets in between 10K and 50K) keep
486-
the true-Mica look. -->
483+
The WinUI raster clip-escape bug that used to spill list rows onto this band (issue #79,
484+
upstream microsoft-ui-xaml#11225) is now held off at the source by the ListView's
485+
CornerRadius="0.1" — see the comment on EntriesList above. That actually clips the rows,
486+
so no opaque backplate is needed here and the true-Mica look is preserved at every list
487+
size. -->
487488
<Grid Grid.Row="3" Visibility="{x:Bind MainViewVisibility, Mode=OneWay}">
488-
<Border Background="{ThemeResource SolidBackgroundFillColorBaseBrush}"
489-
Visibility="{x:Bind StatusBackplateVisibility, Mode=OneWay}"/>
490489
<Border Background="Transparent" Padding="14,5">
491490
<Grid>
492491
<TextBlock Text="{x:Bind StatusText, Mode=OneWay}"

HostsFileEditor.WinUI/MainWindow.xaml.cs

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -178,22 +178,6 @@ private void OnPingActivityChanged(object? sender, EventArgs e)
178178
OnPropertyChanged(nameof(PingProgressVisibility));
179179
}
180180

181-
// Above this many visible rows (at 100% scale), show the opaque backplate behind the status
182-
// bar. WinUI stops clipping the bottom-edge rows of an enormous virtualized list (see the XAML
183-
// comment on the status-bar Grid for the full investigation) and the strays would show through
184-
// the transparent Mica band. Empirically clean at 10K rows and broken between 10K and 50K —
185-
// measured at 200% scale only, which cannot distinguish whether the underlying limit is
186-
// DIP- or physical-pixel-denominated. The escape is raster-level, which favors physical, so the
187-
// row count is scaled by the current RasterizationScale: at 100% the trigger is 10K (the
188-
// measured-safe margin), at 200% it is 5K, at 300% ~3.3K — conservative under either
189-
// hypothesis, while every realistic hosts file keeps the true-Mica look.
190-
private const int StatusBackplateThreshold = 10_000;
191-
192-
public Visibility StatusBackplateVisibility =>
193-
Entries.Count * (Content?.XamlRoot?.RasterizationScale ?? 1.0) > StatusBackplateThreshold
194-
? Visibility.Visible
195-
: Visibility.Collapsed;
196-
197181
// The status row is 0 while the archive view is shown: its content collapses via
198182
// MainViewVisibility, but a FIXED 32px grid row keeps its height regardless — which left a
199183
// permanent dead band of blank Mica under the archive panel.
@@ -531,10 +515,6 @@ private void UpdateStatusCounts()
531515
_statusText = text;
532516
OnPropertyChanged(nameof(StatusText));
533517
}
534-
535-
// Cheap: x:Bind just re-reads Entries.Count and the rasterization scale. Raised on every
536-
// recount so the backplate tracks the visible row count through loads, filters, and bulk edits.
537-
OnPropertyChanged(nameof(StatusBackplateVisibility));
538518
}
539519

540520
// A filter change can swap the entire visible set, so rebuild it with a single bulk rebind
@@ -782,14 +762,7 @@ void ApplyMinimumWindowSize()
782762
}
783763

784764
xamlRootChangedHooked = true;
785-
rootElement.XamlRoot.Changed += (_, _) =>
786-
{
787-
ApplyMinimumWindowSize();
788-
789-
// The backplate trigger is scale-dependent too (raster-level escape —
790-
// see StatusBackplateVisibility).
791-
OnPropertyChanged(nameof(StatusBackplateVisibility));
792-
};
765+
rootElement.XamlRoot.Changed += (_, _) => ApplyMinimumWindowSize();
793766
};
794767
}
795768
}

0 commit comments

Comments
 (0)