powershell 中按钮事件的运行空间

问题描述 投票:0回答:1

不确定这是否重复,在线检查并使用我发现的内容,使用 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()

}

powershell winforms events ipc runspace
1个回答
4
投票

您可以使用它作为您想要执行的操作的蓝图,重要的是运行空间看不到您表单的控件。如果您希望运行空间与控件交互,则必须将它们传递给它,可以通过

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')
}

演示

© www.soinside.com 2019 - 2024. All rights reserved.