PowerShell Add_Click 在 foreach 循环中
PowerShell Add_Click in foreach loop
我想要完成的是创建在单击时在特定目录中启动 exe 文件的按钮,但是当我尝试使用 foreach 循环创建几个按钮时,所有按钮都只是在最后启动文件按钮应该会启动。
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object System.Windows.Forms.Form
$form.Text = 'Main Window'
$form.Size = New-Object System.Drawing.Size(600,400)
$flp = New-Object System.Windows.Forms.FlowLayoutPanel
$flp.Location = New-Object System.Drawing.Point(0,0)
$flp.Height = $form.Height
$flp.Width = $form.Width
$form.Controls.Add($flp)
$files = Get-ChildItem "$home\Downloads" -Include *.exe -Name
foreach ($file in $files){
$button = New-Object System.Windows.Forms.Button
$flp.Controls.Add($button)
$button.Width = 100
$button.Height = 50
$button.Text = $file
$button.Add_Click{
Start-Process -FilePath "$home\Downloads$file"
}
}
$form.Topmost = $true
$form.ShowDialog()
无论我在做什么可能都非常愚蠢,所以我只是在寻找任何替代方案或解决方案,而不是对所有内容进行硬编码。
很可能你需要使用.GetNewClosure()
ScriptBlock method,这样每个脚本块(按钮点击事件)在枚举的时候都保存着$file
变量的当前值。
这意味着什么的例子:
$blocks = foreach($i in 0..5) {
{ "hello $i" }
}
& $blocks[0] # => hello 5
& $blocks[1] # => hello 5
$blocks = foreach($i in 0..5) {
{ "hello $i" }.GetNewClosure()
}
& $blocks[0] # => hello 0
& $blocks[1] # => hello 1
从这个意义上说,假设这是问题所在,以下应该有效:
foreach ($file in $files) {
$button = New-Object System.Windows.Forms.Button
$button.Width = 100
$button.Height = 50
$button.Text = $file
$thisEvent = {
Start-Process -FilePath "$home\Downloads$file"
}.GetNewClosure()
$button.Add_Click($thisEvent)
$flp.Controls.Add($button)
}
可以在 this answer. The .Tag
property of the Button 上看到需要使用 .GetNewClosure()
的一个很好的替代方法可以用来存储文件路径的信息,然后可以在按钮的 .Click
事件:
foreach ($file in $files) {
$button = New-Object System.Windows.Forms.Button
$button.Width = 100
$button.Height = 50
$button.Text = $file
# Store the file's path in the Tag's property of this Button
$button.Tag = "$home\Downloads$file"
$button.Add_Click({
Start-Process -FilePath $this.Tag
})
$flp.Controls.Add($button)
}
我想要完成的是创建在单击时在特定目录中启动 exe 文件的按钮,但是当我尝试使用 foreach 循环创建几个按钮时,所有按钮都只是在最后启动文件按钮应该会启动。
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object System.Windows.Forms.Form
$form.Text = 'Main Window'
$form.Size = New-Object System.Drawing.Size(600,400)
$flp = New-Object System.Windows.Forms.FlowLayoutPanel
$flp.Location = New-Object System.Drawing.Point(0,0)
$flp.Height = $form.Height
$flp.Width = $form.Width
$form.Controls.Add($flp)
$files = Get-ChildItem "$home\Downloads" -Include *.exe -Name
foreach ($file in $files){
$button = New-Object System.Windows.Forms.Button
$flp.Controls.Add($button)
$button.Width = 100
$button.Height = 50
$button.Text = $file
$button.Add_Click{
Start-Process -FilePath "$home\Downloads$file"
}
}
$form.Topmost = $true
$form.ShowDialog()
无论我在做什么可能都非常愚蠢,所以我只是在寻找任何替代方案或解决方案,而不是对所有内容进行硬编码。
很可能你需要使用.GetNewClosure()
ScriptBlock method,这样每个脚本块(按钮点击事件)在枚举的时候都保存着$file
变量的当前值。
这意味着什么的例子:
$blocks = foreach($i in 0..5) {
{ "hello $i" }
}
& $blocks[0] # => hello 5
& $blocks[1] # => hello 5
$blocks = foreach($i in 0..5) {
{ "hello $i" }.GetNewClosure()
}
& $blocks[0] # => hello 0
& $blocks[1] # => hello 1
从这个意义上说,假设这是问题所在,以下应该有效:
foreach ($file in $files) {
$button = New-Object System.Windows.Forms.Button
$button.Width = 100
$button.Height = 50
$button.Text = $file
$thisEvent = {
Start-Process -FilePath "$home\Downloads$file"
}.GetNewClosure()
$button.Add_Click($thisEvent)
$flp.Controls.Add($button)
}
可以在 this answer. The .Tag
property of the Button 上看到需要使用 .GetNewClosure()
的一个很好的替代方法可以用来存储文件路径的信息,然后可以在按钮的 .Click
事件:
foreach ($file in $files) {
$button = New-Object System.Windows.Forms.Button
$button.Width = 100
$button.Height = 50
$button.Text = $file
# Store the file's path in the Tag's property of this Button
$button.Tag = "$home\Downloads$file"
$button.Add_Click({
Start-Process -FilePath $this.Tag
})
$flp.Controls.Add($button)
}