今天的第二个问题,但是这次我相信确实发生了一些奇怪的事情。以下代码不是我的原始代码,我试图用尽可能少的行来重现此行为。在我的原始代码中,我将使用配置文件导入应用程序路径和名称,并在foreach循环中调用CreateButton函数。

我正在尝试创建多个带有应打开不同应用程序的功能的按钮。当我对路径进行硬编码时,一切正常。当我在foreach循环中使用变量时,每个按钮都使用提交的LAST路径。这是有效的代码:

# Define Form
Add-Type -AssemblyName System.Windows.Forms
$form = New-Object Windows.Forms.Form
$form.Size = New-Object Drawing.Size @(260,250)
$Form.Text = "ToolBox"
$form.StartPosition = "CenterScreen"

# Create Button Function
function CreateButton ($ButtonCommand, $ButtonName, $ButtonLocX, $ButtonLocY, $ButtonSizeX, $ButtonSizeY)
{
$btn = New-Object System.Windows.Forms.Button
$btn.add_click($ButtonCommand)
$btn.Text = $ButtonName
$btn.Location = New-Object System.Drawing.Size($ButtonLocX,$ButtonLocY)
$btn.Size = New-Object System.Drawing.Size($ButtonSizeX,$ButtonSizeY)
$form.Controls.Add($btn)
}

$Command={Start-Process -FilePath "C:\Windows\system32\mmc.exe"}
$Text='MMC'
$LocationX=20
$LocationY=10
$SizeX=200
$SizeY=30
CreateButton $Command $Text $LocationX $LocationY $SizeX $SizeY

$Command={Start-Process -FilePath "C:\Windows\regedit.exe"}
$Text='Regedit'
$LocationX=20
$LocationY=70
$SizeX=200
$SizeY=30
CreateButton $Command $Text $LocationX $LocationY $SizeX $SizeY

$Command={Start-Process -FilePath "C:\Windows\System32\cmd.exe"}
$Text='CMD'
$LocationX=20
$LocationY=100
$SizeX=200
$SizeY=30
CreateButton $Command $Text $LocationX $LocationY $SizeX $SizeY

#Show Form
$drc = $form.ShowDialog()

这是无效的代码:
# Define Form
Add-Type -AssemblyName System.Windows.Forms
$form = New-Object Windows.Forms.Form
$form.Size = New-Object Drawing.Size @(260,250)
$Form.Text = "ToolBox"
$form.StartPosition = "CenterScreen"

# Create Button Function
function CreateButton ($ButtonCommand, $ButtonName, $ButtonLocX, $ButtonLocY, $ButtonSizeX, $ButtonSizeY)
{
$btn = New-Object System.Windows.Forms.Button
$btn.add_click($ButtonCommand)
$btn.Text = $ButtonName
$btn.Location = New-Object System.Drawing.Size($ButtonLocX,$ButtonLocY)
$btn.Size = New-Object System.Drawing.Size($ButtonSizeX,$ButtonSizeY)
$form.Controls.Add($btn)
}


$Global:Test="C:\Windows\system32\mmc.exe"
$Command={Start-Process -FilePath $Global:Test}
$Text='MMC'
$LocationX=20
$LocationY=10
$SizeX=200
$SizeY=30
CreateButton $Command $Text $LocationX $LocationY $SizeX $SizeY

$Global:Test="C:\Windows\regedit.exe"
$Command={Start-Process -FilePath $Global:Test}
$Text='Regedit'
$LocationX=20
$LocationY=70
$SizeX=200
$SizeY=30
CreateButton $Command $Text $LocationX $LocationY $SizeX $SizeY

$Global:Test="C:\Windows\System32\cmd.exe"
$Command={Start-Process -FilePath $Global:Test}
$Text='CMD'
$LocationX=20
$LocationY=100
$SizeX=200
$SizeY=30
CreateButton $Command $Text $LocationX $LocationY $SizeX $SizeY

#Show Form
$drc = $form.ShowDialog()

第一个示例创建一个带有3个按钮的表单。当我单击每个按钮时,将启动不同的应用程序。第二个示例创建一个带有3个按钮的表单。当我单击每个按钮时,“CMD.EXE”将打开。当我用代码中的MMC.EXE块更改CMD.EXE时,每个按钮都会打开MMC。谁能解释发生了什么事?

最佳答案

从本质上来说,您希望同一脚本块的不同实例产生不同的结果。为此,您必须将不同的上下文附加到每个脚本块实例。一种方法是将脚本块绑定(bind)到模块。为此,您可以使用GetNewClosure()脚本块实例方法:

$ScriptBlockWithContext=$ScriptBlock.GetNewClosure()

此方法将创建新模块并将所有当前作用域变量捕获到其中。如果您想对要捕获的内容拥有更多的控制权,则可以自己创建模块:
$Module=New-Module {$Context=$Global:Context}
$ScriptBlockWithContext=$Module.NewBoundScriptBlock($ScriptBlock)

如果要引用局部变量,则可以将它们作为附加参数传递给New-Module cmdlet:
$Module=New-Module {param($Context)} $Context
$ScriptBlockWithContext=$Module.NewBoundScriptBlock($ScriptBlock)

另外,您可以在创建模块后调用操作符&.来调用模块范围内的任意代码。特别是,您可以使用New-VariableSet-Variable cmdlet在模块范围内设置变量:
$Module=New-Module {}
& $Module New-Variable Context $Context
$ScriptBlockWithContext=$Module.NewBoundScriptBlock($ScriptBlock)

这里是对代码的简单修改以使其起作用:
# Define Form
Add-Type -AssemblyName System.Windows.Forms
$form = New-Object Windows.Forms.Form
$form.Size = New-Object Drawing.Size @(260,250)
$Form.Text = "ToolBox"
$form.StartPosition = "CenterScreen"

# Create Button Function
function CreateButton ($ButtonCommand, $ButtonName, $ButtonLocX, $ButtonLocY, $ButtonSizeX, $ButtonSizeY)
{
$btn = New-Object System.Windows.Forms.Button
$btn.add_click($ButtonCommand)
$btn.Text = $ButtonName
$btn.Location = New-Object System.Drawing.Size($ButtonLocX,$ButtonLocY)
$btn.Size = New-Object System.Drawing.Size($ButtonSizeX,$ButtonSizeY)
$form.Controls.Add($btn)
}

$CaptureCommand={param($Test)}
$CommonCommand={Start-Process -FilePath $Test}

$Module=New-Module $CaptureCommand "C:\Windows\system32\mmc.exe"
$Command=$Module.NewBoundScriptBlock($CommonCommand)
$Text='MMC'
$LocationX=20
$LocationY=10
$SizeX=200
$SizeY=30
CreateButton $Command $Text $LocationX $LocationY $SizeX $SizeY

$Module=New-Module $CaptureCommand "C:\Windows\regedit.exe"
$Command=$Module.NewBoundScriptBlock($CommonCommand)
$Text='Regedit'
$LocationX=20
$LocationY=70
$SizeX=200
$SizeY=30
CreateButton $Command $Text $LocationX $LocationY $SizeX $SizeY

$Module=New-Module $CaptureCommand "C:\Windows\System32\cmd.exe"
$Command=$Module.NewBoundScriptBlock($CommonCommand)
$Text='CMD'
$LocationX=20
$LocationY=100
$SizeX=200
$SizeY=30
CreateButton $Command $Text $LocationX $LocationY $SizeX $SizeY

#Show Form
$drc = $form.ShowDialog()

关于winforms - Button.add_click中带有变量的启动过程文件路径无法按预期工作,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31077444/

10-13 07:52
查看更多