Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
31 changes: 15 additions & 16 deletions HostsFileEditor.WinUI/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -351,9 +351,19 @@
<TextBlock Text="{x:Bind SelectAllBannerText, Mode=OneWay}" TextWrapping="Wrap"
Foreground="{ThemeResource TextOnAccentFillColorPrimaryBrush}"/>
</Border>
<!-- CornerRadius="0.1" is the fix for the WinUI raster clip-escape bug (issue #79,
upstream microsoft-ui-xaml#11225): once the list's content extent passes ~2^21
DIPs the renderer stops clipping bottom-edge rows and they paint past the list
into the status bar below. Giving the ListView any non-zero CornerRadius forces
a composition geometry clip on its content, which re-establishes the bottom clip
and keeps the strays inside the control. 0.1 is visually indistinguishable from
square. This actually clips (unlike the old opaque backplate, which only occluded
the strays), so it works with the transparent Mica band. Remove once the upstream
bug ships fixed in a Windows App SDK. -->
<ListView x:Name="EntriesList"
Grid.Row="1"
Margin="0,8,0,0"
CornerRadius="0.1"
IsEnabled="{x:Bind IsEntriesInteractive, Mode=OneWay}"
PreviewKeyDown="OnEntriesPreviewKeyDown"
SelectionMode="Extended"
Expand Down Expand Up @@ -470,23 +480,12 @@
window's Mica backdrop; it sits in its own fixed-height grid row, so no list content is
ever laid out behind it.

The backplate underneath exists because of a WinUI composition bug with enormous
virtualized lists: past roughly 2^20 device-independent pixels of panel extent
(~32K rows here), the renderer stops clipping the list's bottom-edge rows — the last
partially-visible row paints in FULL, plus the next cache row — straight through the
ListView's viewport clip, an explicit ancestor UIElement.Clip,
CanContentRenderOutsideBounds=False, and CacheLength=0 (all verified ineffective;
element bounds via UIA stay correct, so it is a raster-level escape, not layout). The
stray pixels land under this transparent band and show through it. They only ever paint
DOWNWARD past the list (title/command bars stay clean), and opaque content drawn later
in the tree occludes them — so when the list is large enough for the bug to trigger,
an opaque backplate in SolidBackgroundFillColorBase (the exact base color Mica tints,
i.e. "Mica minus the desktop tint") slides in behind the text. Normal-sized files
(≤10K rows, empirically clean with margin: breakage sets in between 10K and 50K) keep
the true-Mica look. -->
The WinUI raster clip-escape bug that used to spill list rows onto this band (issue #79,
upstream microsoft-ui-xaml#11225) is now held off at the source by the ListView's
CornerRadius="0.1" — see the comment on EntriesList above. That actually clips the rows,
so no opaque backplate is needed here and the true-Mica look is preserved at every list
size. -->
<Grid Grid.Row="3" Visibility="{x:Bind MainViewVisibility, Mode=OneWay}">
<Border Background="{ThemeResource SolidBackgroundFillColorBaseBrush}"
Visibility="{x:Bind StatusBackplateVisibility, Mode=OneWay}"/>
<Border Background="Transparent" Padding="14,5">
<Grid>
<TextBlock Text="{x:Bind StatusText, Mode=OneWay}"
Expand Down
29 changes: 1 addition & 28 deletions HostsFileEditor.WinUI/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,22 +178,6 @@ private void OnPingActivityChanged(object? sender, EventArgs e)
OnPropertyChanged(nameof(PingProgressVisibility));
}

// Above this many visible rows (at 100% scale), show the opaque backplate behind the status
// bar. WinUI stops clipping the bottom-edge rows of an enormous virtualized list (see the XAML
// comment on the status-bar Grid for the full investigation) and the strays would show through
// the transparent Mica band. Empirically clean at 10K rows and broken between 10K and 50K —
// measured at 200% scale only, which cannot distinguish whether the underlying limit is
// DIP- or physical-pixel-denominated. The escape is raster-level, which favors physical, so the
// row count is scaled by the current RasterizationScale: at 100% the trigger is 10K (the
// measured-safe margin), at 200% it is 5K, at 300% ~3.3K — conservative under either
// hypothesis, while every realistic hosts file keeps the true-Mica look.
private const int StatusBackplateThreshold = 10_000;

public Visibility StatusBackplateVisibility =>
Entries.Count * (Content?.XamlRoot?.RasterizationScale ?? 1.0) > StatusBackplateThreshold
? Visibility.Visible
: Visibility.Collapsed;

// The status row is 0 while the archive view is shown: its content collapses via
// MainViewVisibility, but a FIXED 32px grid row keeps its height regardless — which left a
// permanent dead band of blank Mica under the archive panel.
Expand Down Expand Up @@ -531,10 +515,6 @@ private void UpdateStatusCounts()
_statusText = text;
OnPropertyChanged(nameof(StatusText));
}

// Cheap: x:Bind just re-reads Entries.Count and the rasterization scale. Raised on every
// recount so the backplate tracks the visible row count through loads, filters, and bulk edits.
OnPropertyChanged(nameof(StatusBackplateVisibility));
}

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

xamlRootChangedHooked = true;
rootElement.XamlRoot.Changed += (_, _) =>
{
ApplyMinimumWindowSize();

// The backplate trigger is scale-dependent too (raster-level escape —
// see StatusBackplateVisibility).
OnPropertyChanged(nameof(StatusBackplateVisibility));
};
rootElement.XamlRoot.Changed += (_, _) => ApplyMinimumWindowSize();
};
}
}
Expand Down