不确定这是否重复,在线检查并使用我发现的内容,使用 Boe Prox 的解决方案,该解决方案来自另一篇 StackOverflow 文章参考文献 (https://stackoverflow.com/a/15502286/1546559),但是在他的代码中,他通过在线程内运行的函数从命令行/powershell 窗口进行更新。我正在线程内部的按钮运行一个事件,并尝试为单击事件运行一个单独的线程。在线程之外,该事件工作正常,但在内部,它根本不起作用。我做错了什么? 附言。我发现另一个博客引用了 Boe Prox 的工作(https://www.foxdeploy.com/blog/part-v-powershell-guis-responsive-apps-with-progress-bars.html),构建另一个多线程应用程序,但概念几乎相同,通过 powershell commandlet/函数更新窗口,放置在单独的线程内。
$push.Add_Click{
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
$powershell = [powershell]::Create().AddScript({
$choice = $comboBox.SelectedItem
# $drive = Get-Location
if(!(Test-Path -PathType Container -Path "L:\$choice"))
{
# New-Item -ItemType "container" -Path . -Name $choice
New-Item -ItemType "Directory" -Path . -Name $choice
}
# $folder = $_
# Where is it being stored at?
[System.IO.File]::ReadLines("Y:\$choice\IPs.txt") | foreach {
ping -a -n 2 -w 2000 $_ | Out-Null
Test-Connection -Count 2 -TimeToLive 2 $_ | Out-Null
if($?)
{
RoboCopy /Log:"L:\$folder\$_.log" $source \\$_\c$\tools
RoboCopy /Log+:"L:\$folder\$folder-MovementLogs.log" $source \\$_\c$\tools
Start-Process "P:\psexec.exe" -ArgumentList "\\$_ -d -e -h -s cmd /c reg import C:\tools\dump.reg"
# Copy-Item -LiteralPath Y:\* -Destination \\$_\c$\tools
$listBox.Items.Add($_)
}
}
})
$powershell.Runspace = $newRunspace
$powershell.BeginInvoke()
}
您可以使用它作为您想要执行的操作的蓝图,重要的是运行空间看不到您表单的控件。如果您希望运行空间与控件交互,则必须将它们传递给它,可以通过
SessionStateProxy.SetVariable(...)
或作为参数,例如 .AddParameters(..)
。
using namespace System.Windows.Forms
using namespace System.Drawing
using namespace System.Management.Automation.Runspaces
Add-Type -AssemblyName System.Windows.Forms
[Application]::EnableVisualStyles()
try {
$form = [Form]@{
StartPosition = 'CenterScreen'
Text = 'Test'
WindowState = 'Normal'
MaximizeBox = $false
ClientSize = [Size]::new(200, 380)
FormBorderStyle = 'Fixed3d'
}
$listBox = [ListBox]@{
Name = 'myListBox'
Location = [Point]::new(10, 10)
ClientSize = [Size]::new(180, 300)
}
$form.Controls.Add($listBox)
$runBtn = [Button]@{
Location = [Point]::new(10, $listBox.ClientSize.Height + 30)
ClientSize = [Size]::new(90, 35)
Text = 'Click Me'
}
$runBtn.Add_Click({
$resetBtn.Enabled = $true
if($status['AsyncResult'].IsCompleted -eq $false) {
# we assume it's running
$status['Instance'].Stop()
$this.Text = 'Continue!'
return # end the event here
}
$this.Text = 'Stop!'
$status['Instance'] = $instance
$status['AsyncResult'] = $instance.BeginInvoke()
})
$form.Controls.Add($runBtn)
$resetBtn = [Button]@{
Location = [Point]::new($runBtn.ClientSize.Width + 15, $listBox.ClientSize.Height + 30)
ClientSize = [Size]::new(90, 35)
Text = 'Reset'
Enabled = $false
}
$resetBtn.Add_Click({
if($status['AsyncResult'].IsCompleted -eq $false) {
$status['Instance'].Stop()
}
$runBtn.Text = 'Start!'
$this.Enabled = $false
$listBox.Items.Clear()
})
$form.Controls.Add($resetBtn)
$status = @{}
$rs = [runspacefactory]::CreateRunspace([initialsessionstate]::CreateDefault2())
$rs.ApartmentState = [Threading.ApartmentState]::STA
$rs.ThreadOptions = [PSThreadOptions]::ReuseThread
$rs.Open()
$rs.SessionStateProxy.SetVariable('controls', $form.Controls)
$instance = [powershell]::Create().AddScript({
$listBox = $controls.Find('myListBox', $false)[0]
$ran = [random]::new()
while($true) {
Start-Sleep 1
$listBox.Items.Add($ran.Next())
}
})
$instance.Runspace = $rs
$form.Add_Shown({ $this.Activate() })
$form.ShowDialog()
}
finally {
($form, $instance, $rs).ForEach('Dispose')
}
演示