形式成为焦点
Form takes focus
Add-Type -AssemblyName System.Windows.Forms
$Form = [System.Windows.Forms.Form]::new()
$Form.TopMost = $true
$Form.ShowDialog()
如果我 运行 来自 powershell.exe 的代码,表单不会获得焦点。但是如果我 运行 来自 ISE 的这段代码,焦点就会转移到表单上。为什么会发生这种情况,如何解决?我希望表单不会像 powershell.exe 那样将焦点移开。
UPD
可能 this page 可以在这种情况下提供帮助...
使用 .ShowDialog()
方法调用形式 modally,这意味着您的 PowerShell 脚本的执行被 阻止(无响应) 直到表单 closed.
因此,您必须:
使用.Show()
方法显示形式非模态,确保您的PowerShell脚本继续执行.
- 反过来,这需要您进入一个循环,在其中定期
[System.Windows.Forms.Application]::DoEvents()
调用,以确保表单保持响应。
为了确保调用 .Show()
时窗体不接收焦点,您必须 子类 Forms
class so as to override the ShowWithoutActivation
property,如您所见。
- 反过来,这需要通过
Add-Type
. 使用临时编译的 C# 代码实现子类
警告:如果您还想为表单设置 .TopMost = $true
,以便始终在其他 windows 之上显示表格,需要 解决方法 以在各种主机环境中可靠运行 - 请参阅 底部.
综合起来:
- 注意:启动脚本后按 Ctrl-C 将终止脚本并关闭表单。这有效的事实证明调用者的 window 保持了焦点。
# Derive a custom form class from System.Windows.Forms.Form
# that doesn't activate itself when loaded.
Add-Type -ReferencedAssemblies System.Windows.Forms, System.ComponentModel.Primitives @'
public class MyForm: System.Windows.Forms.Form {
protected override bool ShowWithoutActivation { get { return true; } }
}
'@ -WarningAction Ignore
# Create an instance of the custom form class.
$form = [MyForm]::new()
# Show the form *non-modally*, with .Show() rather than
# .ShowDialog(), which is the prerequisite for not blocking this script.
$form.Show()
# Perform operations while the form is being shown.
try {
do {
# Process form events.
[System.Windows.Forms.Application]::DoEvents()
# Perform operations while the form is being displayed.
Start-Sleep -Milliseconds 200
Write-Host . -NoNewline
} while ($form.Visible)
} finally {
# Make sure that the form gets closed and disposed of.
$form.Dispose()
}
对于反向用例,即如果您想确保表单确实获得焦点 - 默认情况下不会发生一致 - 使用以下内容:
在调用 $Form.ShowDialog()
之前,为 Load
event 添加处理程序以确保表单在加载后接收焦点:
Add-Type -AssemblyName System.Windows.Forms
$form = [System.Windows.Forms.Form]::new()
# Ensure that the form receives the focus on loading.
# (Situationally, especially when run shortly after session startup,
# the form may otherwise end up without the focus.)
$form.add_Load({
$this.Activate()
})
$form.ShowDialog()
解决方法使表单最顶部:
出于我不知道的原因,将表单的 .TopMost
属性 设置为 $true
可能会在(过时的)ISE 中间歇性地安静地发生故障,在Visual Studio 代码(ISE 后继者)以及 Windows 终端。
以下应该解决这些问题。请注意,window 可能会在调用方 window 重新激活之前非常短暂地激活,但在实践中应该不会引起注意:
Add-Type -AssemblyName System.Windows.Forms
# Create a helper type for activating a window by hWnd (window handle)
Add-Type -Namespace Util -Name WinApi -MemberDefinition @'
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
'@
# Create an instance of the custom form class.
$form = [System.Windows.Forms.Form]::new()
# Get the caller's main window handle, to use it for reactivation later.
$thisHWnd = (Get-Process -Id $pid).MainWindowHandle
# Show the form *non-modally*, with .Show() rather than
# .ShowDialog(), which is the prerequisite for not blocking this script.
# Note: This *typically activates* the form (gives it the focus), though not consistently.
$form.Show()
# Perform operations while the form is being shown.
try {
# Set the workaround flags.
$makeTopMost = $true; $reactivateMe = $true
do {
# Process form events.
[System.Windows.Forms.Application]::DoEvents()
# Apply workarounds and reset the flags.
if ($reactivateMe) { $null =[Util.WinApi]::SetForegroundWindow($thisHWnd); $reactivateMe = $false }
if ($makeTopMost) { $form.TopMost = $true; $makeTopMost = $false }
# Perform operations while the form is being displayed.
Start-Sleep -Milliseconds 200
Write-Host ([Util.WinApi]::GetForegroundWindow() -eq $thisHWnd) -NoNewline
} while ($form.Visible)
} finally {
# Make sure that the form gets closed and disposed of.
$form.Dispose()
}
不确定您所说的 “表单没有获得焦点” 是什么意思,但我猜您希望它成为顶级 window。
那么,除了$Form.TopMost = $true
,还要设置TopLevel 属性:
$form.TopLevel = $true
- 顶级 表单是 window 没有父表单,或者其父表单是桌面 window。顶级 windows 通常用作应用程序中的主窗体。
- topmost 表单是一种与所有其他(非最顶层)表单重叠的表单,即使它不是活动表单或前景表单。最顶部的表单始终显示在桌面上 windows z 顺序中的最高点。您可以使用此 属性 创建一个始终显示在您的应用程序中的表单,例如查找和替换工具 window.
- 一个active表单意味着该表单有焦点。
Add-Type -AssemblyName System.Windows.Forms
$Form = [System.Windows.Forms.Form]::new()
$Form.TopMost = $true
$Form.ShowDialog()
如果我 运行 来自 powershell.exe 的代码,表单不会获得焦点。但是如果我 运行 来自 ISE 的这段代码,焦点就会转移到表单上。为什么会发生这种情况,如何解决?我希望表单不会像 powershell.exe 那样将焦点移开。
UPD
可能 this page 可以在这种情况下提供帮助...
使用 .ShowDialog()
方法调用形式 modally,这意味着您的 PowerShell 脚本的执行被 阻止(无响应) 直到表单 closed.
因此,您必须:
使用
.Show()
方法显示形式非模态,确保您的PowerShell脚本继续执行.- 反过来,这需要您进入一个循环,在其中定期
[System.Windows.Forms.Application]::DoEvents()
调用,以确保表单保持响应。
- 反过来,这需要您进入一个循环,在其中定期
为了确保调用
.Show()
时窗体不接收焦点,您必须 子类Forms
class so as to override theShowWithoutActivation
property,如您所见。- 反过来,这需要通过
Add-Type
. 使用临时编译的 C# 代码实现子类
- 反过来,这需要通过
警告:如果您还想为表单设置
.TopMost = $true
,以便始终在其他 windows 之上显示表格,需要 解决方法 以在各种主机环境中可靠运行 - 请参阅 底部.
综合起来:
- 注意:启动脚本后按 Ctrl-C 将终止脚本并关闭表单。这有效的事实证明调用者的 window 保持了焦点。
# Derive a custom form class from System.Windows.Forms.Form
# that doesn't activate itself when loaded.
Add-Type -ReferencedAssemblies System.Windows.Forms, System.ComponentModel.Primitives @'
public class MyForm: System.Windows.Forms.Form {
protected override bool ShowWithoutActivation { get { return true; } }
}
'@ -WarningAction Ignore
# Create an instance of the custom form class.
$form = [MyForm]::new()
# Show the form *non-modally*, with .Show() rather than
# .ShowDialog(), which is the prerequisite for not blocking this script.
$form.Show()
# Perform operations while the form is being shown.
try {
do {
# Process form events.
[System.Windows.Forms.Application]::DoEvents()
# Perform operations while the form is being displayed.
Start-Sleep -Milliseconds 200
Write-Host . -NoNewline
} while ($form.Visible)
} finally {
# Make sure that the form gets closed and disposed of.
$form.Dispose()
}
对于反向用例,即如果您想确保表单确实获得焦点 - 默认情况下不会发生一致 - 使用以下内容:
在调用 $Form.ShowDialog()
之前,为 Load
event 添加处理程序以确保表单在加载后接收焦点:
Add-Type -AssemblyName System.Windows.Forms
$form = [System.Windows.Forms.Form]::new()
# Ensure that the form receives the focus on loading.
# (Situationally, especially when run shortly after session startup,
# the form may otherwise end up without the focus.)
$form.add_Load({
$this.Activate()
})
$form.ShowDialog()
解决方法使表单最顶部:
出于我不知道的原因,将表单的 .TopMost
属性 设置为 $true
可能会在(过时的)ISE 中间歇性地安静地发生故障,在Visual Studio 代码(ISE 后继者)以及 Windows 终端。
以下应该解决这些问题。请注意,window 可能会在调用方 window 重新激活之前非常短暂地激活,但在实践中应该不会引起注意:
Add-Type -AssemblyName System.Windows.Forms
# Create a helper type for activating a window by hWnd (window handle)
Add-Type -Namespace Util -Name WinApi -MemberDefinition @'
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
'@
# Create an instance of the custom form class.
$form = [System.Windows.Forms.Form]::new()
# Get the caller's main window handle, to use it for reactivation later.
$thisHWnd = (Get-Process -Id $pid).MainWindowHandle
# Show the form *non-modally*, with .Show() rather than
# .ShowDialog(), which is the prerequisite for not blocking this script.
# Note: This *typically activates* the form (gives it the focus), though not consistently.
$form.Show()
# Perform operations while the form is being shown.
try {
# Set the workaround flags.
$makeTopMost = $true; $reactivateMe = $true
do {
# Process form events.
[System.Windows.Forms.Application]::DoEvents()
# Apply workarounds and reset the flags.
if ($reactivateMe) { $null =[Util.WinApi]::SetForegroundWindow($thisHWnd); $reactivateMe = $false }
if ($makeTopMost) { $form.TopMost = $true; $makeTopMost = $false }
# Perform operations while the form is being displayed.
Start-Sleep -Milliseconds 200
Write-Host ([Util.WinApi]::GetForegroundWindow() -eq $thisHWnd) -NoNewline
} while ($form.Visible)
} finally {
# Make sure that the form gets closed and disposed of.
$form.Dispose()
}
不确定您所说的 “表单没有获得焦点” 是什么意思,但我猜您希望它成为顶级 window。
那么,除了$Form.TopMost = $true
,还要设置TopLevel 属性:
$form.TopLevel = $true
- 顶级 表单是 window 没有父表单,或者其父表单是桌面 window。顶级 windows 通常用作应用程序中的主窗体。
- topmost 表单是一种与所有其他(非最顶层)表单重叠的表单,即使它不是活动表单或前景表单。最顶部的表单始终显示在桌面上 windows z 顺序中的最高点。您可以使用此 属性 创建一个始终显示在您的应用程序中的表单,例如查找和替换工具 window.
- 一个active表单意味着该表单有焦点。