private/Controls/Add-UiDataGridAlternatingBrush.ps1
|
function Add-UiDataGridAlternatingBrush { <# .SYNOPSIS Alternating, theme aware row stripes that reapply after theme switch. #> [CmdletBinding()] param( [Parameter(Mandatory)] [System.Windows.Controls.DataGrid]$DataGrid ) # Theme changes wipe the stripe. Low priority so the theme finishes first. $gridRef = $DataGrid $applyAlt = { try { $gridRef.SetResourceReference( [System.Windows.Controls.DataGrid]::AlternatingRowBackgroundProperty, 'ButtonHoverBackgroundBrush') } catch { Write-Debug "AlternatingRowBrush apply failed: $_" } }.GetNewClosure() # Explicit Action[string] cast so add_/remove_ThemeChanged both get the identical delegate. # A raw scriptblock rides PS's implicit conversion cache, which drops that delegate under GC pressure... then the unsubscribe does absolutely nothing and the static event traps every closed grid. $themeHandler = [System.Action[string]]{ param($themeName) try { $gridRef.Dispatcher.BeginInvoke( [System.Windows.Threading.DispatcherPriority]::Background, [Action]$applyAlt) | Out-Null } catch { Write-Debug "AlternatingRowBrush re-apply failed: $_" } }.GetNewClosure() # Detach on Window.Closed, never Unloaded. Tab virtualization fires Unloaded on every tab switch, so a hidden then shown grid would miss the theme swap that happened while it was off. $subState = @{ Subscribed = $false } $gridRef.Add_Loaded({ & $applyAlt if (!$subState.Subscribed) { [PsUi.ThemeEngine]::add_ThemeChanged($themeHandler) $subState.Subscribed = $true } }.GetNewClosure()) $detachState = @{ Done = $false } $hookWindow = { if ($detachState.Done) { return } $window = [System.Windows.Window]::GetWindow($gridRef) if (!$window) { return } $detachState.Done = $true # Rebind to locals, nested GetNewClosure only captures the immediate scope, so the closed handler needs $subState/$themeHandler as its own locals or the ThemeChanged unsubscribe gets $null and the static event roots every closed grid. $stateRef = $subState $handlerRef = $themeHandler $window.Add_Closed({ if ($stateRef.Subscribed) { try { [PsUi.ThemeEngine]::remove_ThemeChanged($handlerRef) } catch { Write-Debug "AlternatingRowBrush unsubscribe failed: $_" } $stateRef.Subscribed = $false } }.GetNewClosure()) }.GetNewClosure() # Initialized for grids constructed and torn down without ever loading. Loaded for the standard parent then show path. $gridRef.Add_Initialized({ & $hookWindow }.GetNewClosure()) $gridRef.Add_Loaded({ & $hookWindow }.GetNewClosure()) } |