private/output/Add-DictionaryValuePopupHandler.ps1
|
function Add-DictionaryValuePopupHandler { <# .SYNOPSIS Adds click handler to DataGrid for expanding nested hashtable/array values in a popup. Shows items in a scrollable popup instead of the raw object string. #> [CmdletBinding()] param( [Parameter(Mandatory)] [System.Windows.Controls.DataGrid]$DataGrid ) # Opens the popup for a cell whose Tag holds a dictionary. $DataGrid.Add_PreviewMouseLeftButtonDown({ param($sender, $eventArgs) if ($script:currentDictPopup -and $script:currentDictPopup.IsOpen) { $script:currentDictPopup.IsOpen = $false $script:currentDictPopup = $null } # Only TextBlocks with complex values in their Tag get popups $source = $eventArgs.OriginalSource if ($source -isnot [System.Windows.Controls.TextBlock]) { return } $textBlock = $source $rawValue = $textBlock.Tag if ($null -eq $rawValue) { return } # Arrays go to the array popup, so the two handlers never open over one cell. if ($rawValue -isnot [System.Collections.IDictionary]) { return } if (![PsUi.ValueKind]::IsExpandable($rawValue)) { return } $popupColors = Get-ThemeColors # Build popup at mouse position with offset so mouse is inside $popup = [System.Windows.Controls.Primitives.Popup]@{ StaysOpen = $false AllowsTransparency = $true Placement = 'Mouse' VerticalOffset = -20 HorizontalOffset = -10 } $popupBorder = [System.Windows.Controls.Border]@{ Background = ConvertTo-UiBrush $popupColors.ControlBg BorderBrush = ConvertTo-UiBrush $popupColors.Border BorderThickness = [System.Windows.Thickness]::new(1) CornerRadius = [System.Windows.CornerRadius]::new(4) Padding = [System.Windows.Thickness]::new(12) MaxWidth = 450 MaxHeight = 350 } $popupBorder.Add_MouseLeave({ param($sender, $eventArgs) if ($script:currentDictPopup) { $script:currentDictPopup.IsOpen = $false $script:currentDictPopup = $null } }) $shadow = [System.Windows.Media.Effects.DropShadowEffect]@{ BlurRadius = 10 ShadowDepth = 3 Opacity = 0.3 } $popupBorder.Effect = $shadow $scrollViewer = [System.Windows.Controls.ScrollViewer]@{ VerticalScrollBarVisibility = 'Auto' HorizontalScrollBarVisibility = 'Disabled' } $stackPanel = [System.Windows.Controls.StackPanel]::new() $copyHeader = New-UiPopupCopyHeader -Colors $popupColors $headerRow = $copyHeader.Panel $header = $copyHeader.Title $copyState = $copyHeader.State $copyLines = [System.Collections.Generic.List[string]]::new() $keyCount = [PsUi.ValueKind]::Count($rawValue) $header.Text = if ($keyCount -eq 1) { '1 key:' } else { "$keyCount keys:" } [void]$stackPanel.Children.Add($headerRow) foreach ($entry in $rawValue.GetEnumerator()) { $key = $entry.Key $val = $entry.Value # Switch on the kind string, not the value, since switch enumerates a list value and runs its clauses per element. $displayVal = switch (Get-UiValueKind -Value $val) { 'Null' { '(null)' } 'Bool' { "`$$val" } 'Text' { "'$val'" } 'Dictionary' { "@{...} ($([PsUi.ValueKind]::Count($val)) keys)" } 'List' { "[$([PsUi.ValueKind]::Count($val)) items]" } 'Sequence' { '[sequence]' } default { [PsUi.ValueKind]::DisplayText($val) } } # In a horizontal StackPanel the value gets infinite width and never wraps, so the key docks left and the value takes the rest. $kvPanel = [System.Windows.Controls.DockPanel]@{ Margin = [System.Windows.Thickness]::new(0, 2, 0, 2) } $keyText = [System.Windows.Controls.TextBlock]@{ Text = "$key = " FontWeight = 'SemiBold' VerticalAlignment = 'Top' Foreground = ConvertTo-UiBrush $popupColors.ControlFg } [System.Windows.Controls.DockPanel]::SetDock($keyText, 'Left') [void]$kvPanel.Children.Add($keyText) $valText = [System.Windows.Controls.TextBlock]@{ Text = $displayVal TextWrapping = 'Wrap' Foreground = ConvertTo-UiBrush $popupColors.SecondaryText } [void]$kvPanel.Children.Add($valText) [void]$stackPanel.Children.Add($kvPanel) $copyLines.Add("$key = $displayVal") } $copyState.Text = $copyLines -join [Environment]::NewLine $scrollViewer.Content = $stackPanel $popupBorder.Child = $scrollViewer $popup.Child = $popupBorder $script:currentDictPopup = $popup $popup.IsOpen = $true }.GetNewClosure()) # Close popup when clicking elsewhere $DataGrid.Add_PreviewMouseRightButtonDown({ if ($script:currentDictPopup -and $script:currentDictPopup.IsOpen) { $script:currentDictPopup.IsOpen = $false $script:currentDictPopup = $null } }) } |