【问题标题】:In PowerShell Form.Show() does not work right, but Form.ShowDialog() does在 PowerShell Form.Show() 中无法正常工作,但 Form.ShowDialog() 可以
【发布时间】:2011-08-24 14:34:41
【问题描述】:

我正在尝试通过 powershell 显示图像。我根据this forum post做了一个script

如果我使用ShowDialog(),它可以正常工作,除了在对话框启动时 powershell 执行停止。但是,这是为模态对话框设计的。如果我在 PowershellISE 中调用 Form.Show(),表单会显示,但会冻结并且无法移动或关闭。如果我将代码复制并粘贴到 powershell 控制台,行为是相似的。

如何使对话框非模态,而不是冻结。

【问题讨论】:

标签: winforms powershell modal-dialog


【解决方案1】:

第一个答案为什么附加。

在 Windows 图形程序中,创建 Window 的线程必须在消息泵中循环,以便将来自用户操作的消息重新分配(翻译)到他的 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"

【讨论】:

  • 好吧,对你来说,知识就是一根香肠,还不如让人无知……你是建筑师……
  • x0n “那种问题”让你觉得我不在乎香肠是怎么做的?是的,最后我确实需要 GTD,所以短期内我需要 start-job 或 show-ui。但是,了解“为什么”有助于我评估这里发生的事情。
  • 这不起作用。线程 goForm 不显示任何窗口,因为它不在主线程上...
【解决方案2】:

有很多方法可以使这项工作发挥作用,但没有什么值得花 5 个小时在开放论坛上进行解释的。在 powershell 上还有其他免费的、收缩包装的方法可以做到这一点。最值得注意的是免费的 WPF powershell 工具包:Show-UI at http://showui.codeplex.com/(以前称为 WPK 和/或 PowerBoots - 它们现在已合并。)

【讨论】:

  • @JPBlanc 的 5 分钟解释也是值得的 ;) 为什么?它也适用于其他人一起来并试图弄清楚发生了什么。除此之外,它还可以让@Justin 走得更远,因为他可能会好奇关于消息抽取的所有内容都是关于什么的。两者都 +1...
【解决方案3】:

如果您的目标实际上是在显示图像时不阻塞交互式控制台,那么您仍然可以像使用ShowDialog 一样使用脚本,但您应该使用例如Start-Job 来启动它。因此,对话框仍然是模态的,但它会阻止在另一个运行空间中执行。主运行空间仍可用于调用其他命令。

注意事项:1) 您应该在关闭交互式控制台之前关闭所有打开的对话框。 2) 如果您关心,您应该自己删除已完成的作业(当对话框关闭时,启动它的作业仍然存在)。

我在自定义主机中使用了类似的方法,并且效果很好。我还使用您链接中的脚本对其进行了测试。我稍作改动,将其命名为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

【讨论】:

  • 根据你的说法,我只是意识到 stop-job 或 remove-job 似乎挂在这个功能之王的工作上。你有同样的经历吗?
  • Stop-Job 仅在对话框关闭时结束。 Remove-Job 关闭对话框后工作正常,如果对话框仍然打开,则“无法删除作业......因为作业未完成”失败。
  • Remove-Job -Force 有效,但它也“等待”对话框退出。
  • Roman,似乎当窗口关闭时,作业状态变为“已完成”。那么什么时候需要调用 Stop-Job 呢?是在打开窗口时关闭 powershell/powershellISE 吗?
  • Stop-Job 不是必需的(此外,正如我们所见,它不是很有效)。 Remove-Job 如果您关心仍然存在并消耗一些资源的已完成(他们的窗口已关闭)作业,则可能需要。
【解决方案4】:

以@JPBlanc 的anwer 为基础,使用运行空间也可以(而且更快)。

这是一个基本示例(其余基本保持不变)

$ps = [PowerShell]::Create()
[void]$ps.AddScript({
  Add-Type -AssemblyName System.Windows.Forms
  $form = [Windows.Forms.Form]::new()
  $form.ShowDialog()
})
[void]$ps.BeginInvoke()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-17
    • 1970-01-01
    • 1970-01-01
    • 2023-01-17
    • 1970-01-01
    • 2022-08-05
    • 2014-05-13
    • 1970-01-01
    相关资源
    最近更新 更多