Powershell Checkedlistbox handling - checked item count inconsistency and missed click events

StackOverflow https://stackoverflow.com/questions/21271921

  •  01-10-2022
  •  | 
  •  

Domanda

I'm having trouble with multiple issues with a checkedlistbox. Its content is the Windows feature name (commandline parameter to install a Windows feature via Powershell) and a description which really is its more readable name. Because I develop on Windows 7 and this command is only available on a Server platform I read the data from a XML file source. The XML file was created by the output of function BuildFeaturesFile, below. I've pasted a sample at the bottom if that is a problem.

1) I have to click an item twice to check it.

2) I have to double click an item slowly and surely to avoid the program missing the second click. Would I need to change the Windows control panel config to affect this or if I wanted (not too bothered but more curious) could I reduce the polling time to slicken the interface response?

3) This is my main issue. If I use the mouse to select an item it normally updates the count correctly however when I use the keyboard despite calling the same function I get different results; the first check is seemingly missed (doubled by the look of it reading further online to undo its action - however the event "only" fires once which causes misalignment of the displayed count to the true count. I think it maybe linked to the remark in the ItemCheck event documentation "The check state is not updated until after the ItemCheck event occurs." http://msdn.microsoft.com/en-us/library/system.windows.forms.checkedlistbox.itemcheck(v=vs.110).aspx The main code also updates a description text box but I removed that for brevity.

4) In function ftn_CheckAllItemsInCheckList the top remmed out line works for the first item but as I'm calling it by index seemingly the action of checking the item causes the index to change which unseats the action causing it to break.

Please can you assist - at least with questions #3 and #4 if possible?

Thanks in advance.

Shaun

function BuildForm
{
    # Declare objects
    $frm_BuildConfigurator = New-Object System.Windows.Forms.Form
    $btn_Cancel = New-Object System.Windows.Forms.Button
    $gb_CC_Features = New-Object Windows.Forms.GroupBox
    $clb_CC_Features = New-Object System.Windows.Forms.CheckedListBox
    $btn_CC_Features_UncheckList = New-Object System.Windows.Forms.Button
    $btn_CC_Features_SelectAll = New-Object System.Windows.Forms.Button
    $gb_CCF_Description = New-Object Windows.Forms.GroupBox
    $tb_CCF_Description = New-Object System.Windows.Forms.TextBox

    #Build the form
    $frm_BuildConfigurator.Text = "Build Configurator"
    $frm_BuildConfigurator.StartPosition = "CenterScreen"
    $frm_BuildConfigurator.Width = 380
    $frm_BuildConfigurator.Height = 200
    $frm_BuildConfigurator.FormBorderStyle = "FixedSingle"
    $frm_BuildConfigurator.ControlBox = $false
    $frm_BuildConfigurator.Controls.Add($btn_Cancel)
    #Set default button behaviour
    $frm_BuildConfigurator.KeyPreview = $True
    $frm_BuildConfigurator.Add_KeyDown({if ($_.KeyCode -eq "Enter") {$frm_BuildConfigurator.Close()}})
    $frm_BuildConfigurator.Add_KeyDown({if ($_.KeyCode -eq "Escape") {$frm_BuildConfigurator.Close()}})

    # Create the Cancel button
    $btn_Cancel.Location = New-Object System.Drawing.Size(50,145)
    $btn_Cancel.Size = New-Object System.Drawing.Size(55,23)
    $btn_Cancel.Text = "Cancel"
    $btn_Cancel.Add_Click({$frm_BuildConfigurator.Close()})
    # Create the Features form elements
    $frm_BuildConfigurator.Controls.Add($gb_CC_Features)
    $frm_BuildConfigurator.Controls.Add($gb_CCF_Description)
    # Create the Features group box
    $gb_CC_Features.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
    $gb_CC_Features.Location = New-Object System.Drawing.Point(10,6)
    $gb_CC_Features.Name = "gb_CC_Features"
    $gb_CC_Features.Size = New-Object System.Drawing.Size(350,132)
    $gb_CC_Features.Text = "Features (0 selected)"
    $gb_CC_Features.Controls.Add($clb_CC_Features)
    $gb_CC_Features.Controls.Add($btn_CC_Features_SelectAll)
    $gb_CC_Features.Controls.Add($btn_CC_Features_UncheckList)
    $clb_CC_Features.Location = New-Object Drawing.Point 11,16
    $clb_CC_Features.Size = New-Object System.Drawing.Size(220,110)
    $clb_CC_Features.Add_ItemCheck({ftnUpdateFeatureSelectionCount})
    $clb_CC_Features.Add_SelectedIndexChanged({ftnUpdateFeatureSelectionCount})
    $clb_CC_Features.Add_Click({ftnUpdateFeatureSelectionCount})
    # Populate the Features checked list box
    ForEach ($FeatureItem in $script:xmlFeatures.FeatureList.Feature | Select-Object -Property Name) {
        $clb_CC_Features.Items.Add($FeatureItem.Name) | Out-Null
    }
    # Create the Check All button
    $btn_CC_Features_SelectAll.Location = New-Object System.Drawing.Point(250,20)
    $btn_CC_Features_SelectAll.Size = New-Object System.Drawing.Size(80,23)
    $btn_CC_Features_SelectAll.Text = "Check All"
    $btn_CC_Features_SelectAll.Add_Click({ftn_CheckAllItemsInCheckList $clb_CC_Features})
    $btn_CC_Features_SelectAll.TabIndex = 2
    # Create the Uncheck All button
    $btn_CC_Features_UncheckList.Location = New-Object System.Drawing.Point(250,50)
    $btn_CC_Features_UncheckList.Size = New-Object System.Drawing.Size(80,23)
    $btn_CC_Features_UncheckList.Text = "Uncheck All"
    $btn_CC_Features_UncheckList.Add_Click({ftn_UncheckList $clb_CC_Features})
    $btn_CC_Features_UncheckList.TabIndex = 2

    ftnUpdateFeatureSelectionCount
    #Show the Form
    $frm_BuildConfigurator.ShowDialog() | Out-Null
}

function ftnUpdateFeatureDescription()
{
    $tb_CCF_Description.Text = $script:FeatureDisplayNames[$clb_CC_Features.SelectedIndex]
}

function ftnUpdateFeatureSelectionCount ()
{
    $gb_CC_Features.Text = "Features (" + $clb_CC_Features.CheckedItems.Count + " selected)"
}

function BuildFeaturesFile ()
{
    # Only runs on Windows Server
    $Features = Get-WindowsFeature
    $xml = "<xml>"
    $NewFeaturesFilePath = $ScriptDir + "\FeaturesNew.xml"
    ForEach($Feature in $Features)
    {
        $xml += "<Feature Name='" + $Feature.Name + "' DisplayName='" + $Feature.DisplayName + "'>"
        $xml += "</Feature>"
    }
    $xml += "</xml>"
    $xml | Out-File -FilePath $NewFeaturesFilePath
}

function ReadFeaturesFile ()
{
    [array] $script:FeatureNames = $null
    [array] $script:FeatureDisplayNames = $null
    $FileExists = Test-Path $FeaturesFilePath
    if ($FileExists -eq $true) {
        $script:xmlFeatures.Load($FeaturesFilePath)  
        $xml_Features = $script:xmlFeatures.SelectNodes("/FeatureList/Feature")
        ForEach ($Feature in $xml_Features) {
            [array] $script:FeatureNames += $Feature.Name
            [array] $script:FeatureDisplayNames += $Feature.DisplayName
        }
    }
}

function ftn_UncheckList( $checkedListBoxObject )
{   
    ForEach($i in $checkedListBoxObject.CheckedIndices) { $checkedListBoxObject.SetItemCheckState($i, 'Unchecked') | Out-Null }
}

function ftn_CheckAllItemsInCheckList( $checkedListBoxObject )
{   
    #ForEach($i in $checkedListBoxObject.Items) { $checkedListBoxObject.SetItemChecked($checkedListBoxObject.Items.IndexOf($i), $true)  }
    For($index =0; $index -lt $checkedListBoxItem.Items.Count; $index++){ if($checkedListBoxItem.GetItemChecked($index)) { $checkedListBoxItem.SetItemChecked($i, $true); }}
}

Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Force
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 

$script:xmlFeatures = $null; $script:xmlFeatures = New-Object -TypeName XML
$ScriptPath = $MyInvocation.MyCommand.Path
$ScriptDir = Split-Path -parent $ScriptPath
$FeaturesFilePath = $ScriptDir + "\Features.xml"
$BuildScriptStr = $MyInvocation.MyCommand.Definition #Full path  - for script name only use $MyInvocation.MyCommand.Name
$noSelectedFeatures = 0

ReadFeaturesFile

BuildForm

# End of script

File: Features.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<FeatureList>
   <Feature Name="AD-Certificate" DisplayName="Active Directory Certificate Services"/>
   <Feature Name="ADCS-Cert-Authority" DisplayName="Certification Authority"/>
   <Feature Name="ADCS-Web-Enrollment" DisplayName="Certification Authority Web Enrollment"/>
</FeatureList>
È stato utile?

Soluzione

There are a lot of questions :

1)-2) If you want to click once to check a box you have to set the CheckOnClick property on the CheckedListBox. In you case a line can be checked only once it's selected.

$clb_CC_Features.Size = New-Object System.Drawing.Size(220,110)
$clb_CC_Features.CheckOnClick = $true
$clb_CC_Features.Add_ItemCheck({})

3) The message ItemCheck append before the line is really checked so in the function you call on this even you have look if the line is going to be cheched or unchecked.

I change

$clb_CC_Features.Add_ItemCheck({ftnChecked})
#$clb_CC_Features.Add_SelectedIndexChanged({ftnUpdateFeatureSelectionCount})
#$clb_CC_Features.Add_Click({})

... $_ represent the value of the event.

function ftnChecked ()
{
  if ($_.NewValue -eq 'checked')
  {
    $gb_CC_Features.Text = "Features (" + $($clb_CC_Features.CheckedItems.Count + 1) + " selected)"
  }
  else
  {
    $gb_CC_Features.Text = "Features (" + $($clb_CC_Features.CheckedItems.Count -1) + " selected)"
  }
}

4) You can try the following :

function ftn_CheckAllItemsInCheckList #( $checkedListBoxObject )
{   
    For($index =0; $index -lt $clb_CC_Features.Items.Count; $index++){ $clb_CC_Features.SetItemChecked($index, $true)}
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top