Reputation: 14928
I am trying to display an image via powershell. I made a script based on this forum post.
If I use ShowDialog() it works fine, except the powershell execution stops while the dialog is up. However, that is by design for a modal dialog. If I call Form.Show() in PowershellISE the form shows up, but freezes and cannot be moved or dismissed. Behavior is similar if I copy and past the code to a powershell console.
How do I make the dialog non-modal, and not freeze.
Upvotes: 18
Views: 29115
Reputation: 17035
Building on @JPBlanc's answer, this would also be possible (and faster) using a runspace.
Here's a basic example (the rest would basically remain the same)
$ps = [PowerShell]::Create()
[void]$ps.AddScript({
Add-Type -AssemblyName System.Windows.Forms
$form = [Windows.Forms.Form]::new()
$form.ShowDialog()
})
[void]$ps.BeginInvoke()
Upvotes: 1
Reputation: 42035
If your goal is actually to not block the interactive console when an image is shown then you still can use the script as it is with ShowDialog
but you should start it using, for example, Start-Job
. Thus, the dialog is still modal but it blocks execution in another runspace. The main runspace still can be used for invoking other commands.
Caveats: 1) You should close all opened dialogs before closing the interactive console. 2) If you care, you should remove completed jobs yourself (when a dialog is closed a job that started it still exists).
I use a similar approach in my custom host and it works fine. I also tested it with the script from your link. I changed it slightly so that it is called show-image.ps1
and accepts a file path as a parameter.
This command shows an image and blocks the calling runspace:
show-image.ps1 C:\TEMP\_110513_055058\test.png
This command shows an image and does not block the calling runspace:
Start-Job { show-image.ps1 $args[0] } -ArgumentList C:\TEMP\_110513_055058\test.png
Upvotes: 3
Reputation: 72610
First Answer Why it appends.
In a Windows graphic program the thread which create a Window must loop in a message pump in order to redistribute (translate) messages coming from the user action to events in his Windows.
In a modal window, the modal code that handles the window display runs its own message pump loop and doesn't return until the window is closed. That's why the code after ShowDialog()
won't execute until the window is closed.
Show()
, just ask to show the Window, but if there is no pump loop to manage the messages coming from user action, it just freezes.
Second a simple way to have two threads
The CmdLet start-job use another thread from the pool allocated by Powershell so it makes the dialog non-modal, and it does not freeze.
function goForm
{
[void][reflection.assembly]::LoadWithPartialName("System.Windows.Forms")
$file = (get-item 'C:\temp\jpb.png')
#$file = (get-item "c:\image.jpg")
$img = [System.Drawing.Image]::Fromfile($file);
# This tip from http://stackoverflow.com/questions/3358372/windows-forms-look-different-in-powershell-and-powershell-ise-why/3359274#3359274
[System.Windows.Forms.Application]::EnableVisualStyles();
$form = new-object Windows.Forms.Form
$form.Text = "Image Viewer"
$form.Width = $img.Size.Width;
$form.Height = $img.Size.Height;
$pictureBox = new-object Windows.Forms.PictureBox
$pictureBox.Width = $img.Size.Width;
$pictureBox.Height = $img.Size.Height;
$pictureBox.Image = $img;
$form.controls.add($pictureBox)
$form.Add_Shown( { $form.Activate() } )
$form.ShowDialog()
}
Clear-Host
start-job $function:goForm
$name = Read-Host "What is you name"
Write-Host "your name is $name"
Upvotes: 21