【问题标题】:Checking what closed your Windows Form in Powershell检查在 Powershell 中关闭 Windows 窗体的原因
【发布时间】:2020-03-21 00:40:11
【问题描述】:

想知道是否有办法检查关闭窗口的事件,几乎是点击右上角的红色 x 或者是否调用了 $form.Close()

如果我的脚本中有$form.Add_Closing({}),每个人都会自动启动它,但我想知道关闭窗口的方式是什么。

【问题讨论】:

  • See the Closing event 在 msdn 上。您可以通过将param 块添加到脚本块来匹配签名来利用CancelEventArgs 对象。
  • @mklement0 待定,他们没有明确说明一个或另一个 in 问题。 Relevant documentation
  • 谢谢@TheIncorrigible1,这是正确的链接,但为了节省其他时间:FormClosing 事件的事件参数允许您区分是否表单已通过调用.Close() 或由用户通过标题栏中的关闭按钮关闭。

标签: forms winforms powershell


【解决方案1】:

FormClosing event 参数对象的 .CloseReason 属性不允许您区分已在表单上调用的 .Close() 方法和用户通过标题栏/窗口系统菜单/按 Alt+F4 - 所有这些情况同样导致.CloseReason property反映枚举值UserClosing

但是,您可以通过检查调用堆栈以查找对 .Close() 方法的调用,从而在主题上调整 Reza Aghaei's helpful C# answer 中的技术:

using assembly System.Windows.Forms
using namespace System.Windows.Forms
using namespace System.Drawing

# Create a sample form.
$form = [Form] @{
    ClientSize      = [Point]::new(400,100)
    Text            = 'Closing Demo'
}    

# Create a button and add it to the form.
$form.Controls.AddRange(@(
    ($btnClose = [Button] @{
        Text              = 'Close'
        Location          = [Point]::new(160, 60)
    })
))

# Make the button call $form.Close() when clicked.
$btnClose.add_Click({
  $form.Close()
})

# The event handler called when the form is closing.
$form.add_Closing({
  # Look for a call to a `.Close()` method on the call stack.
  if ([System.Diagnostics.StackTrace]::new().GetFrames().GetMethod().Name -ccontains 'Close') {
    Write-Host 'Closed with .Close() method.'
  } else {
    Write-Host 'Closed via title bar / Alt+F4.'
  }
})

$null = $form.ShowDialog() # Show the form modally.
$form.Dispose()            # Dispose of the form.

如果您运行此代码并尝试各种关闭表单的方法,则会显示一条指示所使用方法的消息(.Close() 调用与标题栏/Alt+F4)。

注意:

  • 通过分配给表单的.CancelButton.SubmitButton 属性但没有明确的$form.Close() 调用的按钮关闭表单仍会导致.Close() 在后台被调用。

  • 代码需要 PowerShell v5+,但它可以适应早期版本。

【讨论】:

    【解决方案2】:

    检查调用堆栈工作正常,您可以依赖它。

    为了完整起见,特别是对于您找到 C# 示例并希望在 PowerShell 中以简单的方式使用它的情况,我将分享一个示例,展示如何处理 WM_SYSCOMMAND,如我的linked post,在 PowerShell 中。

    using assembly System.Windows.Forms
    using namespace System.Windows.Forms
    using namespace System.Drawing
    
    # Create the C# derived Form
    $assemblies = "System.Windows.Forms", "System.Drawing"
    $code = @'
    using System;
    using System.Windows.Forms;
    public class MyForm:Form
    {
        public bool ClosedByXButtonOrAltF4 { get; private set;}
        public const int SC_CLOSE = 0xF060;
        public const int WM_SYSCOMMAND = 0x0112;
        protected override void WndProc(ref Message msg)
        {
            if (msg.Msg == WM_SYSCOMMAND && msg.WParam.ToInt32() == SC_CLOSE)
                ClosedByXButtonOrAltF4 = true;
            base.WndProc(ref msg);
        }
        protected override void OnShown(EventArgs e)
        {
            ClosedByXButtonOrAltF4 = false;
        }    
    }
    '@
    Add-Type -ReferencedAssemblies $assemblies -TypeDefinition $code -Language CSharp   
    
    # Create an instance of MyForm.
    $form = [MyForm] @{
        ClientSize      = [Point]::new(400,100)
        Text            = "Closing Demo"
    }    
    
    # Create a button and add it to the form.
    $form.Controls.AddRange(@(
        ($btnClose = [Button] @{
            Text              = "Close"
            Location          = New-Object System.Drawing.Point 160, 60
        })
    ))
    
    # Make the button call $form.Close() when clicked.
    $btnClose.add_Click({
      $form.Close()
    })
    
    # The event handler called when the form is closing.
    $form.add_Closing({
      if ($form.ClosedByXButtonOrAltF4) {
        Write-Host 'Closed via title bar / Alt+F4.'
      } else {
        Write-Host 'Closed with .Close() method.'
      }
    })
    
    $null = $form.ShowDialog()
    $form.Dispose()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-09-12
      • 2021-01-25
      • 1970-01-01
      • 2010-11-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多