public/controls/New-UiDropdown.ps1
|
function New-UiDropdown { <# .SYNOPSIS Creates a dropdown selection control. .DESCRIPTION Creates a labeled ComboBox for selecting from a list of items. .PARAMETER Label Label text displayed above the dropdown. .PARAMETER Variable Variable name to store selection. .PARAMETER Items Array of selectable items. .PARAMETER Default Initially selected item. .PARAMETER FullWidth Forces the control to take full width in WrapPanel layouts. .PARAMETER EnabledWhen Conditional enabling based on another control's state. Accepts either: - A control proxy (e.g., $toggleControl) - enables when that control is truthy - A scriptblock (e.g., { $toggle -and $userName }) - enables when expression is true Truthy values: CheckBox=checked, TextBox=non-empty, ComboBox=has selection. .PARAMETER ClearIfDisabled When used with -EnabledWhen, resets the dropdown selection when it becomes disabled. .PARAMETER OnChange ScriptBlock to execute when the selection changes. Receives the new selection value as the first parameter. .PARAMETER WPFProperties Hashtable of additional WPF properties to set on the control. Allows setting any valid WPF property not explicitly exposed as a parameter. Invalid properties will generate warnings but not stop execution. Supports attached properties using dot notation (e.g., "Grid.Row"). .EXAMPLE New-UiDropdown -Label "Color" -Variable "color" -Items @('Red','Green','Blue') -WPFProperties @{ ToolTip = "Pick a color" } .EXAMPLE New-UiDropdown -Label "Environment" -Variable "env" -Items @('Dev','Staging','Prod') -OnChange { param($selected) Write-Host "Switched to: $selected" } #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$Label, [Parameter(Mandatory)] [string]$Variable, [Parameter(Mandatory)] [string[]]$Items, [string]$Default, [switch]$FullWidth, [Parameter()] [object]$EnabledWhen, [Parameter()] [switch]$ClearIfDisabled, [scriptblock]$OnChange, [Parameter()] [hashtable]$WPFProperties ) try { $session = Assert-UiSession -CallerName 'New-UiDropdown' Write-Debug "Label='$Label', Variable='$Variable', Items=$($Items.Count)" $colors = Get-ThemeColors $parent = $session.CurrentParent Write-Debug "Parent: $($parent.GetType().Name)" $stack = [System.Windows.Controls.StackPanel]@{ Margin = [System.Windows.Thickness]::new(4, 4, 4, 8) } $labelBlock = [System.Windows.Controls.TextBlock]@{ Text = $Label FontSize = 12 Foreground = ConvertTo-UiBrush $colors.ControlFg Margin = [System.Windows.Thickness]::new(0, 0, 0, 4) Tag = 'ControlFgBrush' } [PsUi.ThemeEngine]::RegisterElement($labelBlock) [void]$stack.Children.Add($labelBlock) $combo = [System.Windows.Controls.ComboBox]@{ Height = 28 } Set-ComboBoxStyle -ComboBox $combo # Use AsyncObservableCollection + ItemsSource so Add-UiListItem/Remove-UiListItem # work at runtime from background threads (same pattern as New-UiList). $collection = [PsUi.AsyncObservableCollection[object]]::new() foreach ($item in $Items) { [void]$collection.Add($item) } $combo.ItemsSource = $collection $session.RegisterListCollection($Variable, $collection) if ($Default -and $Items -contains $Default) { $combo.SelectedItem = $Default } elseif ($Items.Count -gt 0) { $combo.SelectedIndex = 0 } [void]$stack.Children.Add($combo) # Tag wrapper for FormLayout unwrapping in New-UiGrid Set-UiFormControlTag -Wrapper $stack -Label $labelBlock -Control $combo # FullWidth in WrapPanel contexts Set-FullWidthConstraint -Control $stack -Parent $parent -FullWidth:$FullWidth # Apply custom WPF properties if specified if ($WPFProperties) { Set-UiProperties -Control $stack -Properties $WPFProperties } Write-Debug "Adding to $($parent.GetType().Name)" [void]$parent.Children.Add($stack) # Register control in all session registries Register-UiControlComplete -Name $Variable -Control $combo -InitialValue $combo.SelectedItem # Wire up OnChange callback - store in Tag so the event handler can access it if ($OnChange) { if (!$combo.Tag -or $combo.Tag -isnot [hashtable]) { $combo.Tag = @{} } $combo.Tag['OnChange'] = $OnChange $combo.Add_SelectionChanged({ param($sender, $e) $tag = $sender.Tag if (!$tag -or !$tag.OnChange) { return } $selectedValue = $sender.SelectedItem try { & $tag.OnChange $selectedValue } catch { Write-Warning "OnChange callback error: $_" } }) } # Wire up conditional enabling if specified if ($EnabledWhen) { Register-UiCondition -TargetControl $combo -Condition $EnabledWhen -ClearIfDisabled:$ClearIfDisabled } } catch { Write-Debug "ERROR: $($_.Exception.Message)" Write-Debug "STACK: $($_.ScriptStackTrace)" throw } } |