【问题标题】:Refresh Array checkboxes with Powershell使用 Powershell 刷新数组复选框
【发布时间】:2021-11-07 10:30:30
【问题描述】:

我正在尝试创建一个脚本,让用户从下拉列表中选择服务器。每个服务器都映射到一个唯一的数组,该数组进入一个 foreach 循环。循环遍历数组,并在表单上打印一个带有数组中值的复选框。这没有问题。问题是当我从下拉列表中选择不同的服务器并单击“选择服务器”按钮时,数组中的新值不会覆盖现有值。换句话说,表单上的复选框值不会使用新的数组值进行更新。我希望发生的是,当您单击“选择服务器”按钮时,复选框值会更新以反映与其相应服务器关联的数组值。

这是一个例子。

  1. 从下拉列表中选择 ServerA
  2. 选择“选择服务器”
  3. 以下复选框将在复选框的表单中列出:@('Zero','One','Two','Three')
  4. 现在,如果您单击 ServerB 并选择“选择服务器”,我希望新的复选框会用这些值覆盖现有的复选框:@('0','1','2','3')李>

不幸的是,这些值没有更新。 I need to have the array values update when the "Select Server" button is selected... Ive looked around at forums and have found some possible solutions but they all seems to fall short.

提前谢谢你。

function GenerateForm 
{   
$PC=
{
    $hostname = $dropdown.SelectedItem
    
    if ($hostname -eq "ServerA")

        { $CheckBoxLabels = @('Zero','One','Two','Three')
        }
    elseif($hostname -eq "ServerB")
        {
           $CheckBoxLabels = @('0','1','2','3')
     }
        
    $name = New-Object System.Windows.Forms.Label -Property @{
    Text = "Start Time"
    Location = "900, 220"
    ForeColor = "Black"
    Height = 22
    Width = 200
    }
    $form1.Controls.Add($hostname)
        
    $CheckBoxCounter = 1
    
    $CheckBoxes = foreach($Label in $CheckBoxLabels) 
    {   
        $CheckBox = New-Object System.Windows.Forms.CheckBox        
        $CheckBox.UseVisualStyleBackColor = $True
        $System_Drawing_Size = New-Object System.Drawing.Size
        $System_Drawing_Size.Width = 104
        $System_Drawing_Size.Height = 24
        $CheckBox.Size = $System_Drawing_Size
        $CheckBox.TabIndex = 2
    
        $CheckBox.Text = $Label
        
        $System_Drawing_Point = New-Object System.Drawing.Point
        $System_Drawing_Point.X = 27
        # Make sure to vertically space them dynamically, counter comes in handy
        $System_Drawing_Point.Y = 200 + (($CheckBoxCounter - 1) * 31) #Controls location on Y axis
        $CheckBox.Location = $System_Drawing_Point
        $CheckBox.DataBindings.DefaultDataSourceUpdateMode = 0

        # Give it a unique name based on our counter
        $CheckBox.Name = "CheckBox$CheckBoxCounter"

       $form1.Controls.Add($CheckBox)

        # return object ref to array
        $Global:CheckBox
        # increment our counter
        $CheckBoxCounter++
    }
    }

    $form1 = New-Object System.Windows.Forms.Form
    $form1.Text = "UCCE Log Collector - Version 2.0"
    $form1.Name = "form1"
    $form1.DataBindings.DefaultDataSourceUpdateMode = 0
    $System_Drawing_Size = New-Object System.Drawing.Size
    $System_Drawing_Size.Width = 1150
    $System_Drawing_Size.Height = 500
    $form1.ClientSize = $System_Drawing_Size

$dropdown = New-Object System.Windows.Forms.ListBox
$dropdown.Location = New-Object System.Drawing.Point(10,50)
$dropdown.Size = New-Object System.Drawing.Size(100,20)
$dropdown.Height = 80

[void] $dropdown.Items.Add('ServerA')
[void] $dropdown.Items.Add('ServerB')


$form1.Controls.Add($dropdown)

    ######### Select Server Button
    $SelectPC = New-Object System.Windows.Forms.Button
    $SelectPC.TabIndex = 4
    $SelectPC.Name = "SelectPC"
    $System_Drawing_Size = New-Object System.Drawing.Size
    $System_Drawing_Size.Width = 120
    $System_Drawing_Size.Height = 30
    $SelectPC.Size = $System_Drawing_Size
    $SelectPC.UseVisualStyleBackColor = $True
    $SelectPC.Text = "Select Server"
    $System_Drawing_Point = New-Object System.Drawing.Point
    $System_Drawing_Point.X = 0 # 0
    $System_Drawing_Point.Y = 150 #150
    $SelectPC.Location = $System_Drawing_Point
    $SelectPC.DataBindings.DefaultDataSourceUpdateMode = 0
    $SelectPC.add_Click($PC)

    $form1.Controls.Add($SelectPC)
    
        $result = $form1.ShowDialog()
    $result

}
GenerateForm

【问题讨论】:

  • 您是说第一次选择服务器时它可以工作,但之后就不行了?您永远不会设置任何CheckBoxCheckedCheckState 属性。每次选择服务器时,您都在现有控件之上添加新控件,而无需删除或重用已有的控件。我相信$CheckBox.Name = "CheckBox$CheckBoxCounter" 也会导致名称冲突,因为每次$CheckBoxCounter 都从1 开始。
  • 正确,如果我选择 ServerA 或 ServerB,复选框将生成相应的数组。但是,如果我随后选择一个新服务器,它不会替换表单上的现有阵列。你有没有机会分享一个关于我如何解决这个问题的例子?
  • 我明白了,从第一次加载开始,您仍然看到相同的 Text。不是每次调用Click/$PC 时都创建CheckBoxes,而是希望在创建$form1 之后创建它们一次(与使用$dropdown$SelectPC 的方式相同)并存储它们在单独的变量中,或者更好的是,一个数组。那么当Click/$PC 被调用时,你只需设置他们的Text 和我想Checked 属性。
  • 你能分享一个我可以使用的例子吗?这对我有很大帮助。

标签: arrays powershell winforms checkbox powershell-5.0


【解决方案1】:

根据请求in the comments 为每个主机提供可变数量的属性,首先我们将创建一个Panel 来保存我们的CheckBoxes 并将其添加到我们的Form...

# Create a Panel to contain the dynamic collection of CheckBoxes
$HostPropertiesPanel = New-Object -TypeName 'System.Windows.Forms.Panel' -Property @{
    # To illustrate the changing Size of the Panel
    BackColor = [System.Drawing.Color]::GreenYellow
    Location  = New-Object -TypeName 'System.Drawing.Point' -Property @{
        X = 27
        Y = 200
    }
    Name      = 'HostPropertiesPanel'
    Size      = [System.Drawing.Size]::Empty
}
$form1.Controls.Add($HostPropertiesPanel)

这消除了我们自己跟踪CheckBoxes 的需要,因为我们知道它们都包含在这个Panel 中。 Size 最初是 Empty,因为在选择主机之前不会显示 CheckBoxes。

Click/$PC 内部,我们将更改主机属性的定义方式...

# Set $hostProperties to a Hashtable array for the corresponding value of $hostname
# The IsChecked values are arbitrary for demonstration purposes
#TODO: Replace if...elseif with a switch statement; see "help about_Switch"
$hostProperties = if ($hostname -eq "ServerA") {
    @{ Label = 'Zero';  IsChecked = $false },
    @{ Label = 'One';   IsChecked = $true },
    @{ Label = 'Two';   IsChecked = $true },
    @{ Label = 'Three'; IsChecked = $false }
}
elseif ($hostname -eq "ServerB") {
    @{ Label = '0'; IsChecked = $true },
    @{ Label = '1'; IsChecked = $false },
    @{ Label = '2'; IsChecked = $false },
    @{ Label = '3'; IsChecked = $true }
}
elseif ($hostname -eq "ServerC") {
    @{ Label = 'A'; IsChecked = $true },
    @{ Label = 'B'; IsChecked = $true },
    @{ Label = 'C'; IsChecked = $false }
}
elseif ($hostname -eq "ServerD") {
    # Create a property (Hashtable) for each day of the week
    [Enum]::GetNames([DayOfWeek]) | ForEach-Object -Process {
        @{
            Label     = $_
            # Check the box if the day name has an odd number of vowels
            IsChecked = [Regex]::Matches($_, '[aeiou]').Count % 2 -eq 1
        }
    }
}
else {
    # Oops!  A host with no properties defined was selected...
}

我们不是使用一个数组来存储标签,而另一个数组来存储CheckBox 状态,而是根据已选择的主机获得一个Hashtables 数组并将其存储在$hostProperties 中。

在我们创建新的CheckBoxes 之前,我们必须从$HostPropertiesPanel 中删除任何现有的,并根据所选主机属性的Length 调整其大小...

# Remove all existing CheckBoxes from the Panel
$HostPropertiesPanel.Controls.Clear()
# Resize the Panel to accommodate the new count of host properties
$HostPropertiesPanel.Size = New-Object -TypeName 'System.Drawing.Size' -Property @{
    Width  = 104
    Height = if ($hostProperties.Length -gt 0) {
        ($hostProperties.Length - 1) * 31 + 24
    }
    else {
        0
    }
}

然后我们只需要调整创建和配置每个CheckBox的代码...

for ($index = 0; $index -lt $hostProperties.Length; $index++) {
    $CheckBox = New-Object System.Windows.Forms.CheckBox
    $CheckBox.UseVisualStyleBackColor = $True
    $System_Drawing_Size = New-Object System.Drawing.Size
    $System_Drawing_Size.Width = 104
    $System_Drawing_Size.Height = 24
    $CheckBox.Size = $System_Drawing_Size
    $CheckBox.TabIndex = 2

    $CheckBox.Text = $hostProperties[$index].Label
    $CheckBox.Checked = $hostProperties[$index].IsChecked

    $System_Drawing_Point = New-Object System.Drawing.Point
    $System_Drawing_Point.X = 0
    # Make sure to vertically space them dynamically, counter comes in handy
    $System_Drawing_Point.Y = $index * 31 #Controls location on Y axis
    $CheckBox.Location = $System_Drawing_Point
    $CheckBox.DataBindings.DefaultDataSourceUpdateMode = 0

    # Give it a unique name based on our counter
    $CheckBox.Name = "CheckBox$index"

    $HostPropertiesPanel.Controls.Add($CheckBox)
}

关键更改是使用$hostProperties 中的$index 的当前值检索新CheckBoxTextChecked 值。

最后的改动是更新主机名列表...

$dropdown.Items.AddRange(
    @('ServerA', 'ServerB', 'ServerC', 'ServerD', 'ServerX')
)
$form1.Controls.Add($dropdown)

完整的脚本如下所示...

function GenerateForm {
    $PC = {
        $hostname = $dropdown.SelectedItem
        # Set $hostProperties to a Hashtable array for the corresponding value of $hostname
        # The IsChecked values are arbitrary for demonstration purposes
        #TODO: Replace if...elseif with a switch statement; see "help about_Switch"
        $hostProperties = if ($hostname -eq "ServerA") {
            @{ Label = 'Zero';  IsChecked = $false },
            @{ Label = 'One';   IsChecked = $true },
            @{ Label = 'Two';   IsChecked = $true },
            @{ Label = 'Three'; IsChecked = $false }
        }
        elseif ($hostname -eq "ServerB") {
            @{ Label = '0'; IsChecked = $true },
            @{ Label = '1'; IsChecked = $false },
            @{ Label = '2'; IsChecked = $false },
            @{ Label = '3'; IsChecked = $true }
        }
        elseif ($hostname -eq "ServerC") {
            @{ Label = 'A'; IsChecked = $true },
            @{ Label = 'B'; IsChecked = $true },
            @{ Label = 'C'; IsChecked = $false }
        }
        elseif ($hostname -eq "ServerD") {
            # Create a property (Hashtable) for each day of the week
            [Enum]::GetNames([DayOfWeek]) | ForEach-Object -Process {
                @{
                    Label     = $_
                    # Check the box if the day name has an odd number of vowels
                    IsChecked = [Regex]::Matches($_, '[aeiou]').Count % 2 -eq 1
                }
            }
        }
        else {
            # Oops!  A host with no properties defined was selected...
        }

        # Don't execute any layout logic until all changes are complete
        $HostPropertiesPanel.SuspendLayout()
        # Remove all existing CheckBoxes from the Panel
        $HostPropertiesPanel.Controls.Clear()
        # Resize the Panel to accommodate the new count of host properties
        $HostPropertiesPanel.Size = New-Object -TypeName 'System.Drawing.Size' -Property @{
            Width  = 104
            Height = if ($hostProperties.Length -gt 0) {
                ($hostProperties.Length - 1) * 31 + 24
            }
            else {
                0
            }
        }

        for ($index = 0; $index -lt $hostProperties.Length; $index++) {
            $CheckBox = New-Object System.Windows.Forms.CheckBox
            $CheckBox.UseVisualStyleBackColor = $True
            $System_Drawing_Size = New-Object System.Drawing.Size
            $System_Drawing_Size.Width = 104
            $System_Drawing_Size.Height = 24
            $CheckBox.Size = $System_Drawing_Size
            $CheckBox.TabIndex = 2

            $CheckBox.Text = $hostProperties[$index].Label
            $CheckBox.Checked = $hostProperties[$index].IsChecked

            $System_Drawing_Point = New-Object System.Drawing.Point
            $System_Drawing_Point.X = 0
            # Make sure to vertically space them dynamically, counter comes in handy
            $System_Drawing_Point.Y = $index * 31 #Controls location on Y axis
            $CheckBox.Location = $System_Drawing_Point
            $CheckBox.DataBindings.DefaultDataSourceUpdateMode = 0

            # Give it a unique name based on our counter
            $CheckBox.Name = "CheckBox$index"

            $HostPropertiesPanel.Controls.Add($CheckBox)
        }

        # All changes are complete, so resume layout logic
        $HostPropertiesPanel.ResumeLayout()
    }

    $form1 = New-Object System.Windows.Forms.Form
    $form1.Text = "UCCE Log Collector - Version 2.0"
    $form1.Name = "form1"
    $form1.DataBindings.DefaultDataSourceUpdateMode = 0
    $System_Drawing_Size = New-Object System.Drawing.Size
    $System_Drawing_Size.Width = 1150
    $System_Drawing_Size.Height = 500
    $form1.ClientSize = $System_Drawing_Size

    $dropdown = New-Object System.Windows.Forms.ListBox
    $dropdown.Location = New-Object System.Drawing.Point(10, 50)
    $dropdown.Size = New-Object System.Drawing.Size(100, 20)
    $dropdown.Height = 80

    $dropdown.Items.AddRange(
        @('ServerA', 'ServerB', 'ServerC', 'ServerD', 'ServerX')
    )
    $form1.Controls.Add($dropdown)

    ######### Select Server Button
    $SelectPC = New-Object System.Windows.Forms.Button
    $SelectPC.TabIndex = 4
    $SelectPC.Name = "SelectPC"
    $System_Drawing_Size = New-Object System.Drawing.Size
    $System_Drawing_Size.Width = 120
    $System_Drawing_Size.Height = 30
    $SelectPC.Size = $System_Drawing_Size
    $SelectPC.UseVisualStyleBackColor = $True
    $SelectPC.Text = "Select Server"
    $System_Drawing_Point = New-Object System.Drawing.Point
    $System_Drawing_Point.X = 0 # 0
    $System_Drawing_Point.Y = 150 #150
    $SelectPC.Location = $System_Drawing_Point
    $SelectPC.DataBindings.DefaultDataSourceUpdateMode = 0
    $SelectPC.add_Click($PC)

    $form1.Controls.Add($SelectPC)

    # Create a Panel to contain the dynamic collection of CheckBoxes
    $HostPropertiesPanel = New-Object -TypeName 'System.Windows.Forms.Panel' -Property @{
        # To illustrate the changing Size of the Panel
        BackColor = [System.Drawing.Color]::GreenYellow
        Location  = New-Object -TypeName 'System.Drawing.Point' -Property @{
            X = 27
            Y = 200
        }
        Name      = 'HostPropertiesPanel'
        Size      = [System.Drawing.Size]::Empty
    }
    $form1.Controls.Add($HostPropertiesPanel)

    $name = New-Object System.Windows.Forms.Label -Property @{
        Text      = "Start Time"
        Location  = "900, 220"
        ForeColor = "Black"
        Height    = 22
        Width     = 200
    }
    $form1.Controls.Add($name)

    $result = $form1.ShowDialog()
    $result
}
GenerateForm

另一种方法,特别是对于大量主机属性,将Panel 及其内容替换为CheckedListBox

【讨论】:

  • 哇!谢谢兰斯!!如果没有您的专业知识,我不会想到这一点。
  • 不客气。我已经编辑了我的答案,以便 $PC 设置 $checkBox.Checked 在处理非样本数据时更直接。
  • Lance 我还有最后一个问题。该代码总是产生 4 个复选框。我需要它根据数组“CheckBoxLabels”中有多少值来动态创建复选框。我似乎无法让它相应地更新。你能帮忙吗?
  • 我已经更新了我的答案以使用每个主机的可变数量的属性。
  • 谢谢兰斯!我非常感谢您的帮助和回应。你帮了我很大的忙。
猜你喜欢
  • 2012-03-10
  • 1970-01-01
  • 2014-11-18
  • 2017-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-20
  • 2019-02-19
相关资源
最近更新 更多