Кнопки формы Powershell работают только на последней вкладке - PullRequest
1 голос
/ 03 февраля 2020

Я пытаюсь создать форму, которая будет включать / отключать устройства, которые могут разбудить Windows машину. Идея заключается в том, что вы перемещаете устройства, которые хотите включить, из одного списка в другой для каждой машины. У меня есть вкладки форм Powershell, динамически генерируемые для каждой машины, а также кнопки «Добавить», «Удалить», «Ок» и «Отмена» на каждой вкладке. Но всякий раз, когда я запускаю код на реальных машинах, кнопки «Добавить» и «Удалить» перемещают только выбранные устройства на последней вкладке, а не на первых двух. Кнопки «ОК» и «Отмена» работают должным образом на всех вкладках.

Я подозреваю, что что-то не присваивается уникально каждой паре кнопок «Добавить» / «Удалить» во время Foreach-Object l oop, оставляя только последнюю вкладку в l oop работающей, но я не могу понять, чего мне не хватает.

Полный код:

$_ComputerList = @("Computer01","Computer02","Computer03")
$_HashComputerTable = @{}
$_HashFormTabTable = @{}
$_HashDevices = @{}
$_PotentialItems = @()
$_EnabledItems = @()

Foreach ($_Computer in $_ComputerList) {
    $_HashComputerTable[$_Computer] = @(
        $_PotentialDevicesList = [System.Collections.ArrayList]@(Invoke-Command -ComputerName $_Computer -ScriptBlock {powercfg /DEVICEQUERY wake_programmable} | Where  {$_ -ne ""})
        $_EnabledDevicesList = [System.Collections.ArrayList]@(Invoke-Command -ComputerName $_Computer -ScriptBlock {powercfg /devicequery wake_armed} | Where  {$_ -ne ""} )
        $_PotentialDevicesList = [System.Collections.ArrayList]@(Compare-Object -ReferenceObject $_PotentialDevicesList -DifferenceObject $_EnabledDevicesList | Select -ExpandProperty InputObject)
        New-Object -TypeName PSObject -Property @{
            PotentialDevices = $_PotentialDevicesList
            EnabledDevices = $_EnabledDevicesList
            }
        )
    }

Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()

$Form              = New-Object system.Windows.Forms.Form
$FormSizeWidth     = 985
$FormSizeHeight    = 560
$Form.MinimumSize  = "$FormSizeWidth,$FormSizeHeight"
$Form.MaximumSize  = "$FormSizeWidth,$FormSizeHeight"
#$Form.ClientSize  = "$FormSizeWidth,$FormSizeHeight"
$Form.FormBorderStyle = 'Fixed3D'
$Form.MaximizeBox  = $false
$Form.text         = "Form"
$Form.TopMost      = $false

$TabBox            = New-object System.Windows.Forms.TabControl
$TabBox.DataBindings.DefaultDataSourceUpdateMode = 0
$TabBox.Location   = New-Object System.Drawing.size(5,5)
$TabBox.Name       = "tabControl"
$TabBox.Width      = $FormSizeWidth - 27
$TabBox.Height     = $FormSizeHeight - 57
$TabBox.Anchor     = "Top, Bottom, Left, Right"
$Form.Controls.Add($TabBox)

Foreach ($_Computer in $_ComputerList){
    $_HashFormTabTable[$_Computer] = New-Object -TypeName PSObject -Property @{
        Tab          = New-Object System.Windows.Forms.TabPage
        PotentialBox = New-Object system.Windows.Forms.ListBox
        EnabledBox   = New-Object system.Windows.Forms.ListBox
        PotentialLabel = New-Object system.Windows.Forms.Label
        EnabledLabel   = New-Object system.Windows.Forms.Label
        AddButton      = New-Object system.Windows.Forms.Button
        RemoveButton   = New-Object system.Windows.Forms.Button
        }
####Tab
    $_HashFormTabTable[$_Computer].Tab.DataBindings.DefaultDataSourceUpdateMode = 0
    $_HashFormTabTable[$_Computer].Tab.UseVisualStyleBackColor = $True
    $_HashFormTabTable[$_Computer].Tab.Name = "$_Computer"
    $_HashFormTabTable[$_Computer].Tab.Text = "$_Computer"
    $TabBox.Controls.Add($_HashFormTabTable[$_Computer].Tab)

####PotentialBox
    $_HashFormTabTable[$_Computer].PotentialBox.location           = New-Object System.Drawing.Point(10,30)
    $_HashFormTabTable[$_Computer].PotentialBox.Font               = New-Object System.Drawing.Font("Lucida Console",10,[System.Drawing.FontStyle]::Regular)
    $_HashFormTabTable[$_Computer].PotentialBox.text               = "PotentialBox_" + "$_Computer"
    $_HashFormTabTable[$_Computer].PotentialBox.width              = 395
    $_HashFormTabTable[$_Computer].PotentialBox.height             = 440
    $_HashFormTabTable[$_Computer].PotentialBox.SelectionMode      = 'MultiExtended'
    $_HashFormTabTable[$_Computer].Tab.Controls.Add($_HashFormTabTable[$_Computer].PotentialBox)

####EnabledBox
    $_HashFormTabTable[$_Computer].EnabledBox.location             = New-Object System.Drawing.Point(540,30)
    $_HashFormTabTable[$_Computer].EnabledBox.Font                 = New-Object System.Drawing.Font("Lucida Console",10,[System.Drawing.FontStyle]::Regular)
    $_HashFormTabTable[$_Computer].EnabledBox.text                 = "EnabledBox_" + "$_Computer"
    $_HashFormTabTable[$_Computer].EnabledBox.width                = 395
    $_HashFormTabTable[$_Computer].EnabledBox.height               = 440
    $_HashFormTabTable[$_Computer].EnabledBox.SelectionMode        = 'MultiExtended'
    $_HashFormTabTable[$_Computer].Tab.Controls.Add($_HashFormTabTable[$_Computer].EnabledBox)

####PotentialLabel
    $_HashFormTabTable[$_Computer].PotentialLabel.location         = New-Object System.Drawing.Point(19,10)
    $_HashFormTabTable[$_Computer].PotentialLabel.text             = "Potential to Wake Device"
    $_HashFormTabTable[$_Computer].PotentialLabel.AutoSize         = $true
    $_HashFormTabTable[$_Computer].PotentialLabel.width            = 25
    $_HashFormTabTable[$_Computer].PotentialLabel.height           = 10
    $_HashFormTabTable[$_Computer].PotentialLabel.Font             = 'Microsoft Sans Serif,10'
    $_HashFormTabTable[$_Computer].Tab.Controls.Add($_HashFormTabTable[$_Computer].PotentialLabel)

####EnabledLabel
    $_HashFormTabTable[$_Computer].EnabledLabel.location           = New-Object System.Drawing.Point(575,10)
    $_HashFormTabTable[$_Computer].EnabledLabel.text               = "Enabled to Wake Device"
    $_HashFormTabTable[$_Computer].EnabledLabel.AutoSize           = $true
    $_HashFormTabTable[$_Computer].EnabledLabel.width              = 25
    $_HashFormTabTable[$_Computer].EnabledLabel.height             = 10
    $_HashFormTabTable[$_Computer].EnabledLabel.Font               = 'Microsoft Sans Serif,10'
    $_HashFormTabTable[$_Computer].Tab.Controls.Add($_HashFormTabTable[$_Computer].EnabledLabel)

####AddButton
    $_HashFormTabTable[$_Computer].AddButton.Name                  = "AddButton_$_Computer"
    $_HashFormTabTable[$_Computer].AddButton.location              = New-Object System.Drawing.Point(440,140) 
    $_HashFormTabTable[$_Computer].AddButton.text                  = "-->"
    $_HashFormTabTable[$_Computer].AddButton.width                 = 70
    $_HashFormTabTable[$_Computer].AddButton.height                = 30
    $_HashFormTabTable[$_Computer].AddButton.Font                  = 'Microsoft Sans Serif,10'
    $_HashFormTabTable[$_Computer].AddButton.Add_Click({
        $_PotentialItems = @($_HashFormTabTable[$_Computer].PotentialBox.SelectedItems)
        $_PotentialItems | Foreach{
            $_HashFormTabTable[$_Computer].EnabledBox.Items.Add($_)
            $_HashFormTabTable[$_Computer].PotentialBox.Items.Remove($_)
            }
        })
    $_HashFormTabTable[$_Computer].Tab.Controls.Add($_HashFormTabTable[$_Computer].AddButton)

####RemoveButton
    $_HashFormTabTable[$_Computer].RemoveButton.Name               = "RemoveButton_$_Computer"
    $_HashFormTabTable[$_Computer].RemoveButton.location           = New-Object System.Drawing.Point(440,185)
    $_HashFormTabTable[$_Computer].RemoveButton.text               = "<--"
    $_HashFormTabTable[$_Computer].RemoveButton.width              = 70
    $_HashFormTabTable[$_Computer].RemoveButton.height             = 30
    $_HashFormTabTable[$_Computer].RemoveButton.Font               = 'Microsoft Sans Serif,10'
    $_HashFormTabTable[$_Computer].RemoveButton.Add_Click({
        $_EnabledItems = @($_HashFormTabTable[$_Computer].EnabledBox.SelectedItems)
        $_EnabledItems | Foreach{
            $_HashFormTabTable[$_Computer].PotentialBox.Items.Add($_)
            $_HashFormTabTable[$_Computer].EnabledBox.Items.Remove($_)
            }
        })
    $_HashFormTabTable[$_Computer].Tab.Controls.Add($_HashFormTabTable[$_Computer].RemoveButton)

####OkButton
    $OkButton                        = New-Object system.Windows.Forms.Button
    $OkButton.location               = New-Object System.Drawing.Point(440,230)
    $OkButton.text                   = "Ok"
    $OkButton.width                  = 70
    $OkButton.height                 = 30
    $OkButton.Font                   = 'Microsoft Sans Serif,10'
    $OkButton.Add_Click({OkClick})
    $_HashFormTabTable[$_Computer].Tab.Controls.Add($OkButton)

####CancelButton
    $CancelButton                    = New-Object system.Windows.Forms.Button
    $CancelButton.location           = New-Object System.Drawing.Point(440,275)
    $CancelButton.text               = "Cancel"
    $CancelButton.width              = 70
    $CancelButton.height             = 30
    $CancelButton.Font               = 'Microsoft Sans Serif,10'
    $CancelButton.Add_Click({CancelClick})
    $_HashFormTabTable[$_Computer].Tab.Controls.Add($CancelButton)
    }

function OkClick {
    Foreach ($_Computer in $_ComputerList) {
        $_HashDevices[$_Computer] = New-Object -TypeName PSObject -Property @{
            PotentialDevices = @($_HashFormTabTable[$_Computer].PotentialBox.items)
            EnabledDevices = @($_HashFormTabTable[$_Computer].EnabledBox.items)
            }
        }
    $Form.Close()
    }

function CancelClick { 
    $Form.Close()
    }

Foreach ($_Computer in $_ComputerList){
    $_HashComputerTable[$_Computer].PotentialDevices | Foreach {if ($_ -ne $null) {[void] $_HashFormTabTable[$_Computer].PotentialBox.Items.Add($_)}}
    $_HashComputerTable[$_Computer].EnabledDevices | Foreach {if ($_ -ne $null) {[void] $_HashFormTabTable[$_Computer].EnabledBox.Items.Add($_)}}
    }

[void]$Form.ShowDialog()

1 Ответ

0 голосов
/ 04 февраля 2020

Я изучил новый метод PowerShell пару дней go - GetNewClosure() - и с тех пор это уже третий вопрос, на который я ответил, который его использует: -).

* 1003 Во-первых, я немного упростил ваш код, потому что вам не нужно хранить ссылки на все ваши элементы управления в глобальном массиве. Затем я также добавил вызов к GetNewClosure() в ваши скриптовые блоки обратного вызова.

(упрощенный) код:

Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()

$Form           = New-Object system.Windows.Forms.Form
$Form.Width     = 985
$Form.Height    = 560

$TabBox          = New-object System.Windows.Forms.TabControl
$TabBox.Location = New-Object System.Drawing.size(5,5)
$TabBox.Dock     = "Fill"
$Form.Controls.Add($TabBox)

foreach ($item in @("page1", "page2", "page3") )
{

#### tab page
    $tabPage = New-Object System.Windows.Forms.TabPage
    $tabPage.DataBindings.DefaultDataSourceUpdateMode = 0
    $tabPage.Text = $item
    $tabBox.Controls.Add($tabPage)

#### disabled listbox
    $disabledList = New-Object system.Windows.Forms.ListBox
    $disabledList.location = New-Object System.Drawing.Point(10,30)
    $disabledList.width    = 395
    $disabledList.height   = 440
    $disabledList.SelectionMode = 'MultiExtended'
    @( "aaa", "bbb" ) | % { $disabledList.Items.Add($_) }
    $tabPage.Controls.Add($disabledList)

#### enabled listbox
    $enabledList = New-Object system.Windows.Forms.ListBox
    $enabledList.location = New-Object System.Drawing.Point(540,30)
    $enabledList.width    = 395
    $enabledList.height   = 440
    $enabledList.SelectionMode = 'MultiExtended'
    @( "ccc", "ddd" ) | % { $enabledList.Items.Add($_) }
    $tabPage.Controls.Add($enabledList)

#### add button
    $addButton = New-Object system.Windows.Forms.Button
    $addButton.location = New-Object System.Drawing.Point(440,140) 
    $addButton.text     = "-->"
    $addButton.width    = 70
    $addButton.height   = 30
    $tabPage.Controls.Add($addButton)

    $addButton.Add_Click(
        {
            @( $disabledList.SelectedItems ) | Foreach {
                $enabledList.Items.Add($_)
                $disabledList.Items.Remove($_)
            }
        }.GetNewClosure()
    )

#### remove button
    $removeButton = New-Object system.Windows.Forms.Button
    $removeButton.location = New-Object System.Drawing.Point(440,185)
    $removeButton.text     = "<--"
    $removeButton.width    = 70
    $removeButton.height   = 30
    $removeButton.Add_Click(
        {
            @( $enabledList.SelectedItems ) | Foreach {
                $disabledList.Items.Add($_)
                $enabledList.Items.Remove($_)
            }
        }.GetNewClosure()
    )
    $tabPage.Controls.Add($removeButton)

####OkButton
    $OkButton          = New-Object system.Windows.Forms.Button
    $OkButton.location = New-Object System.Drawing.Point(440,230)
    $OkButton.text     = "Ok"
    $OkButton.width    = 70
    $OkButton.height   = 30
    $OkButton.Add_Click({OkClick})
    $tabPage.Controls.Add($OkButton)

####CancelButton
    $CancelButton          = New-Object system.Windows.Forms.Button
    $CancelButton.location = New-Object System.Drawing.Point(440,275)
    $CancelButton.text     = "Cancel"
    $CancelButton.width    = 70
    $CancelButton.height   = 30
    $CancelButton.Font     = 'Microsoft Sans Serif,10'
    $CancelButton.Add_Click({CancelClick})
    $tabPage.Controls.Add($CancelButton)

}

function OkClick {
    $Form.Close()
}

function CancelClick { 
    $Form.Close()
}

[void]$Form.ShowDialog()

Короче говоря, ваши исходные обратные вызовы вычисляли выражение $_HashFormTabTable[$_Computer].PotentialBox, например, во время выполнения обратного вызова , а не при создании сценария обратного вызова создания .

Обратите внимание, что PowerShell сохраняет последнее значение итератора переменная при выходе foreach l oop - например,

PS> foreach ($x in @("aaa", "bbb", "ccc") ) {}
PS> $x
ccc

, поэтому, когда любой ваших обратных вызовов выполнялся, они все получали последний элемент в массиве $_HashFormTabTable потому что значение $_Computer было последним значением, итерированным в for для l oop.

Сравните поведение этого скрипта, например:

$callbacks = @();
foreach( $item in @( "aaa", "bbb", "ccc" ) )
{
    $callbacks += { write-host "callback = '$item'" }
}
write-host "item = '$item'";
foreach( $callback in $callbacks )
{
    $callback.Invoke()
}

, который выводит

item = 'ccc'
callback = 'ccc'
callback = 'ccc'
callback = 'ccc'

с этим:

$callbacks = @();
foreach( $item in @( "aaa", "bbb", "ccc" ) )
{
    $callbacks += { write-host "callback = '$item'" }.GetNewClosure()
}
write-host "item = '$item'"
foreach( $callback in $callbacks )
{
    $callback.Invoke()
}

, который выводит:

item = 'ccc'
callback = 'aaa'
callback = 'bbb'
callback = 'ccc'

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...