public/dialogs/Show-UiSaveDialog.ps1
|
function Show-UiSaveDialog { <# .SYNOPSIS Shows a file save dialog. .DESCRIPTION Show-UiFilePicker's counterpart for picking a destination, parented the same way. Returns the target path, $null on cancel. Writing the file is still your job. .PARAMETER Title Dialog title. .PARAMETER Filter File type filter. .PARAMETER DefaultName Default file name. .PARAMETER InitialDirectory Starting folder path when the dialog opens. .EXAMPLE $path = Show-UiSaveDialog -Filter 'CSV files|*.csv' -DefaultName 'export.csv' #> [CmdletBinding()] param( [string]$Title = 'Save File', [string]$Filter = 'All files|*.*', [string]$DefaultName, [string]$InitialDirectory ) Write-Debug "Title='$Title' Filter='$Filter' DefaultName='$DefaultName'" # The dialog needs to run on an STA thread with a message pump $showDialog = { param($dialogTitle, $dialogFilter, $defaultFileName, $initialDir) Add-Type -AssemblyName PresentationFramework $dialog = [Microsoft.Win32.SaveFileDialog]::new() $dialog.Title = $dialogTitle $dialog.Filter = $dialogFilter if ($defaultFileName) { $dialog.FileName = $defaultFileName } if ($initialDir -and (Test-Path $initialDir)) { $dialog.InitialDirectory = $initialDir } $result = $dialog.ShowDialog() if ($result -eq $true) { return $dialog.FileName } return $null } # If we're inside a PsUi window, use its dispatcher to show the dialog $session = Get-UiSession -ErrorAction SilentlyContinue if ($session -and $session.Window) { # We have a window, use its dispatcher return $session.Window.Dispatcher.Invoke([Func[object]]{ $dialog = [Microsoft.Win32.SaveFileDialog]::new() $dialog.Title = $Title $dialog.Filter = $Filter if ($DefaultName) { $dialog.FileName = $DefaultName } if ($InitialDirectory -and (Test-Path $InitialDirectory)) { $dialog.InitialDirectory = $InitialDirectory } $result = $dialog.ShowDialog($session.Window) if ($result -eq $true) { return $dialog.FileName } return $null }) } # No UI context - run in STA runspace $runspace = [runspacefactory]::CreateRunspace() $runspace.ApartmentState = 'STA' $runspace.ThreadOptions = 'ReuseThread' $runspace.Open() $ps = [powershell]::Create() $ps.Runspace = $runspace [void]$ps.AddScript($showDialog) [void]$ps.AddArgument($Title) [void]$ps.AddArgument($Filter) [void]$ps.AddArgument($DefaultName) [void]$ps.AddArgument($InitialDirectory) try { $result = $ps.Invoke() Write-Debug "Result: $result" return $result } finally { $ps.Dispose() $runspace.Dispose() } } |