PowerShell .NET 如果选择了所有子节点,则仅检索父节点

PowerShell .NET Retrieve only parent node if all child nodes are selected

我想知道如何在父节点的所有子节点都被 selected 时只检索父节点的名称。在下面的代码中,函数 Get-CheckedNodes 检索前面带有复选标记的所有内容。

在下面的示例中,如果您 select 'Cars > Blue' 它将 return:Lamborghini、Maserati 和 Blue。这是正确的,但我只想让它报告父级 'Blue',因为一切都是 selected。然而,当只有一辆车 selected 时,它应该只报告那一辆车而不是它的父车。

代码:

Function Add-Node($Nodes, $Path) {  
    $Path.Split("/") | % {
        Write-Verbose "Searching For: $_"
        $SearchResult = $Nodes.Find($_, $False)

    If ($SearchResult.Count -eq 1) {
      Write-Verbose "Selecting: $($SearchResult.Name)"
      $Nodes = $SearchResult[0].Nodes
    }
    Else {
      Write-Verbose "Adding: $_"
      $Node = New-Object Windows.Forms.TreeNode($_)
      $Node.Name = $_
      $Nodes.Add($Node)  | Out-Null
    }
  }
}

Function Get-CheckedNodes($nodes) {
    foreach ($n in $Nodes) {
        if ($n.nodes.count -gt 0) {
            Get-CheckedNodes $n.nodes
        }
        if ($n.checked) {
            Write-Output $n.Name
        }           
    }   
}

Function Select-ChildNodes($node) {
    $checkStatus = $node.Checked
    foreach ($n in $node.Nodes) {
        $n.checked = $checkstatus
        Select-ChildNodes($n)
    }
}

Function Select-ParentNode($node) {
    $parent = $node.Parent
    if($parent -eq $null) {
        return
    }
    $parent.checked = $true
    foreach ($n in $parent.Nodes) {
        if(!$n.checked) {
            $parent.Checked = $false
            break
        }  
    }
    Select-ParentNode($parent)
}

$script:SelectedOU = $null

Add-Type -AssemblyName System.Windows.Forms
$Form = New-Object System.Windows.Forms.Form
$Form.ClientSize = '342, 502'
$Form.FormBorderStyle = 'FixedDialog'

$ButtonOK_Click = {
    if ($script:SelectedOU = Get-CheckedNodes $treeView.Nodes) {
        $Form.close()
    }
    elseif (([System.Windows.Forms.MessageBox]::Show(
                "You haven't selected anything.`nAre you sure you want to leave?", 
                "Oops!",'YesNo','Information')) -eq 'Yes') {$Form.close()}
}

$Treeview_AfterCheck = {
    $Treeview.Remove_AfterCheck($Treeview_AfterCheck)
    Select-ChildNodes($_.node)
    Select-ParentNode($_.node)
    $Treeview.Add_AfterCheck($Treeview_AfterCheck)
}

$TreeView = New-Object System.Windows.Forms.TreeView
$TreeView.Dock = 'Fill'
$TreeView.CheckBoxes = $true
$Treeview.Add_AfterCheck($Treeview_AfterCheck)

Add-Node $TreeView.Nodes "Fruits"  
Add-Node $TreeView.Nodes "Vegetables"  
Add-Node $TreeView.Nodes "Cars" 
Add-Node $TreeView.Nodes "Cars/Blue" 
Add-Node $TreeView.Nodes "Cars/Blue/Lamborghini"
Add-Node $TreeView.Nodes "Cars/Blue/Maserati"
Add-Node $TreeView.Nodes "Cars/Red" 
Add-Node $TreeView.Nodes "Cars/Red/Lamborghini"
Add-Node $TreeView.Nodes "Cars/Red/Maserati"

$ButtonCancel = New-Object System.Windows.Forms.Button
$ButtonCancel.text = “&Cancel”
$ButtonCancel.Location = '120,467'
$ButtonCancel.size = '75,23'
$ButtonCancel.Anchor = 'Bottom, Left'
$ButtonCancel.add_Click({$Form.close()})
$Form.Controls.Add($ButtonCancel)

$ButtonOK = New-Object System.Windows.Forms.Button
$ButtonOK.Location = '245,467'
$ButtonOK.Size = '75,23'
$ButtonOK.Name = 'ButtonOK'
$ButtonOK.Text = 'OK'
$ButtonOK.add_Click($ButtonOK_Click)
$Form.Controls.Add($ButtonOK)
$Form.Controls.Add($TreeView)
$Form.ShowDialog() > $null

$script:SelectedOU

感谢您的帮助。

一种方法是在写入节点的文本之前添加一个额外的检查来查找当前级别未检查的内容,这仅发生在 Get-CheckedNodes 函数中。

因此,如果当前级别中至少有一个节点未被选中,则选中的将写入输出,否则什么都不写。因为如果当前级别的所有节点都被选中,父级将被选中并且它的文本将被写入输出。此外,如果一个节点被选中,那么它的所有子节点都会被选中。所以这应该适用于所有情况。

Function Get-CheckedNodes($nodes) {

    $allChecked = $true
    foreach ($n in $Nodes) 
    {
        if (!$n.checked) {
            $allChecked = $false
            break
        }
    }
    foreach ($n in $Nodes) 
    {
        if ($n.nodes.count -gt 0) {
            Get-CheckedNodes $n.nodes
        }
        if ($n.checked -and $allChecked -eq $false) {
            Write-Output $n.Name
        }           
    }   
}