private/Controls/Add-UiDataGridFrozenColumnAccent.ps1
|
function Add-UiDataGridFrozenColumnAccent { <# .SYNOPSIS Vertical 2px accent line between the last frozen column and the scrolling region. #> [CmdletBinding()] param( [Parameter(Mandatory)] [System.Windows.Controls.DataGrid]$DataGrid, [Parameter(Mandatory)] [int]$FrozenColumns ) if ($FrozenColumns -le 0 -or $DataGrid.Columns.Count -eq 0) { return } $resolveRightmost = { # Highest visible DisplayIndex inside the frozen range, not the exact edge index. Filtering on Visibility keeps the accent off a hidden column. Taking the max keeps it drawing when HideEmptyColumns collapsed the edge column itself. $DataGrid.Columns | Where-Object { $_.DisplayIndex -le ($FrozenColumns - 1) -and $_.Visibility -eq [System.Windows.Visibility]::Visible } | Sort-Object DisplayIndex -Descending | Select-Object -First 1 }.GetNewClosure() $rightmost = & $resolveRightmost if (!$rightmost) { return } $thickness = [System.Windows.Thickness]::new(0, 0, 2, 0) # Brush in the grid's Resources stays themeable. Stuffing it in a Style freezes it and severs the DynamicResource link to AccentColor. $resourceKey = '__FrozenColumnFadedAccent' if (!$DataGrid.Resources.Contains($resourceKey)) { $faded = [System.Windows.Markup.XamlReader]::Parse(@' <SolidColorBrush xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Color="{DynamicResource AccentColor}" Opacity="0.5"/> '@) $DataGrid.Resources.Add($resourceKey, $faded) } # Reapply when columns reorder so the accent follows the new frozen edge. $applyAccent = { param($targetCol) if (!$targetCol) { return } $cellAccentRef = [System.Windows.DynamicResourceExtension]::new($resourceKey) $headerAccentRef = [System.Windows.DynamicResourceExtension]::new($resourceKey) # Base the new style on whatever cell style is already there so the theme's hover and selection states don't get wiped along with the border setters. $baseCellStyle = $targetCol.CellStyle if (!$baseCellStyle) { $baseCellStyle = $DataGrid.CellStyle } $cellStyle = if ($baseCellStyle) { [System.Windows.Style]::new([System.Windows.Controls.DataGridCell], $baseCellStyle) } else { [System.Windows.Style]::new([System.Windows.Controls.DataGridCell]) } [void]$cellStyle.Setters.Add([System.Windows.Setter]::new([System.Windows.Controls.DataGridCell]::BorderThicknessProperty, $thickness)) [void]$cellStyle.Setters.Add([System.Windows.Setter]::new([System.Windows.Controls.DataGridCell]::BorderBrushProperty, $cellAccentRef)) # Negative top/bottom margin bleeds the accent over the row gridlines so the line draws solid, not dashed. Costs a remeasure on every container recycle (negative margin invalidates the layout slot). Padding and Border background don't reach past the cell. [void]$cellStyle.Setters.Add([System.Windows.Setter]::new([System.Windows.FrameworkElement]::MarginProperty, [System.Windows.Thickness]::new(0, -1.5, 0, -1.5))) # Selected cells get the row's highlight brush. Clear the negative margins too - otherwise they bleed onto adjacent cells when selected and the seam shows. $selectedTrigger = [System.Windows.Trigger]::new() $selectedTrigger.Property = [System.Windows.Controls.DataGridCell]::IsSelectedProperty $selectedTrigger.Value = $true [void]$selectedTrigger.Setters.Add([System.Windows.Setter]::new([System.Windows.FrameworkElement]::MarginProperty, [System.Windows.Thickness]::new(0))) [void]$cellStyle.Triggers.Add($selectedTrigger) $targetCol.CellStyle = $cellStyle $baseHeaderStyle = $targetCol.HeaderStyle if (!$baseHeaderStyle) { $baseHeaderStyle = $DataGrid.ColumnHeaderStyle } $headerStyle = if ($baseHeaderStyle) { [System.Windows.Style]::new([System.Windows.Controls.Primitives.DataGridColumnHeader], $baseHeaderStyle) } else { [System.Windows.Style]::new([System.Windows.Controls.Primitives.DataGridColumnHeader]) } [void]$headerStyle.Setters.Add([System.Windows.Setter]::new([System.Windows.Controls.Primitives.DataGridColumnHeader]::BorderThicknessProperty, $thickness)) [void]$headerStyle.Setters.Add([System.Windows.Setter]::new([System.Windows.Controls.Primitives.DataGridColumnHeader]::BorderBrushProperty, $headerAccentRef)) $targetCol.HeaderStyle = $headerStyle }.GetNewClosure() & $applyAccent $rightmost # Reorder retargets the accent. Strip styles off the previous rightmost on the way through so the line doesn't double up if the user drags the frozen edge column elsewhere. $previousRightmost = @{ Col = $rightmost } $DataGrid.add_ColumnReordered({ param($sender, $eventArgs) $newRightmost = & $resolveRightmost if (!$newRightmost -or $newRightmost -eq $previousRightmost.Col) { return } if ($previousRightmost.Col) { try { $previousRightmost.Col.CellStyle = $null } catch { } try { $previousRightmost.Col.HeaderStyle = $null } catch { } } & $applyAccent $newRightmost $previousRightmost.Col = $newRightmost }.GetNewClosure()) } |