В PowerShell Form.Show() работает неправильно, но Form.ShowDialog() делает

Я пытаюсь отобразить изображение через powershell. Я сделал script на основе этот пост форума.

Если я использую ShowDialog(), он отлично работает, за исключением того, что выполнение powershell прекращается во время разговора. Тем не менее, это дизайн для модального диалога. Если я вызываю Form.Show() в PowershellISE, форма появляется, но зависает и не может быть перемещена или удалена. Поведение аналогично, если я копирую и прохожу код в консоль powershell.

Как сделать диалог немодальным, а не заморозить.

Ответы

Ответ 1

Первый ответ Почему он добавляет.

В графической программе Windows поток, который создает Окно, должен зацикливаться на насосе сообщений, чтобы перераспределять (переводить) сообщения, поступающие от действия пользователя, к событиям в его Windows.

В модальном окне модальный код, обрабатывающий оконный дисплей, запускает собственный контур насоса сообщений и не возвращается, пока окно не будет закрыто. Поэтому код после ShowDialog() не будет выполняться до закрытия окна.

Show(), просто попросите показать окно, но если для управления сообщениями, поступающими от действия пользователя, нет контура насоса, он просто зависает.

Второй простой способ иметь два потока

В начале работы CmdLet используется другой поток из пула, выделенного Powershell, поэтому он делает диалог немодальным и не замерзает.

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"

Ответ 2

Есть способы сделать эту работу, но ничто не стоит тратить пять часов на объяснение на открытом форуме. Есть и другие бесплатные, с термоусадочными способами сделать это на PowerShell. В первую очередь со свободным набором инструментов PowerWoot WPF: Show-UI на http://showui.codeplex.com/ (ранее известный как WPK и/или PowerBoots - они теперь объединены. )

Ответ 3

Если ваша цель состоит в том, чтобы не блокировать интерактивную консоль при показе изображения, вы все равно можете использовать script, как и в случае с ShowDialog, но вы должны запустить его, используя, например, Start-Job. Таким образом, диалог по-прежнему модальный, но он блокирует выполнение в другой области. Основное рабочее пространство все еще может использоваться для вызова других команд.

Предостережения: 1) Перед закрытием интерактивной консоли необходимо закрыть все открытые диалоги. 2) Если вам все равно, вы должны сами удалить выполненные задания (когда диалог закрыт заданием, которое его начало все еще существует).

Я использую подобный подход в своем пользовательском хосте, и он отлично работает. Я также проверил его с помощью script по вашей ссылке. Я немного изменил его так, что он называется show-image.ps1 и принимает путь к файлу в качестве параметра.

Эта команда показывает изображение и блокирует вызывающую область:

show-image.ps1 C:\TEMP\_110513_055058\test.png

Эта команда показывает изображение и не блокирует вызывающую область:

Start-Job { show-image.ps1 $args[0] } -ArgumentList C:\TEMP\_110513_055058\test.png