winforms Windows Form Foreach remove只删除一半Form.Control元素

e5nqia27  于 2023-10-23  发布在  Windows
关注(0)|答案(2)|浏览(132)

为什么不删除所有元素?
代码:

$AAD = New-Object system.Windows.Forms.CheckBox
    $AAD.Name = 'AAD'
    $AAD.text = 'AAD'
    $AAD.Checked = $true 
    $AAD.AutoSize = $true
    $AAD.width = 47
    $AAD.height = 30
    $AAD.enabled = $true
    $AAD.location = New-Object System.Drawing.Point(12, 76)
    $AAD.Font = New-Object System.Drawing.Font('Microsoft Sans Serif', 10)

    $AD = New-Object system.Windows.Forms.CheckBox
    $AD.Name = 'AD'
    $AD.text = 'AD'
    $AD.Checked = $true 
    $AD.AutoSize = $true
    $AD.width = 45
    $AD.height = 20
    $AD.location = New-Object System.Drawing.Point(64, 76)
    $AD.Font = New-Object System.Drawing.Font('Microsoft Sans Serif', 10)

    $array = @('AAD', 'AD')
    $Form.Controls | where { $array -contains $_.Name } | foreach { $Form.Controls.RemoveByKey($_.Name) }

如果我记录它找到的元素的名称,它会记录这一点(所以它确实找到了两者,但不会删除它们):

AAD
AD
rekjcdws

rekjcdws1#

我无法解释为什么它无法删除其中一个控件,但我可以为您提供一种更强大的方法,使用.Remove而不是.RemoveByKey不会有这样的问题:

$form.Controls.AddRange(@($AD; $AAD))
'AAD', 'AD' | ForEach-Object {
    foreach ($control in $Form.Controls.Find($_, $true)) {
        $form.Controls.Remove($control)
    }
}
$form.Controls.Count # 0

关于Jimi's的有用评论:
保留一半控件的原因是在foreach循环中删除元素会修改您正在迭代的集合。反向for循环是常见的对策之一--通常,您应该处理不再需要的控件,而不是删除它们。Controls.Remove()不会释放任何东西(不过,在.NET 5+中,这种行为有些不同)。
在迭代集合的同时修改集合可以解释OP的问题,而反向for循环的解决方案也可以解决这个问题。我个人仍然坚持使用这个答案中显示的前面的方法,使用.Find.Remove

$array = @('AAD', 'AD')
for ($i = $form.Controls.Count - 1; $i -ge 0; $i--) {
    $control = $Form.Controls[$i]
    if ($control.Name -in $array) {
        $Form.Controls.RemoveByKey($control.Name) # -> Not needed
        # Disposing the control also removes it from the control collection
        $control.Dispose()
    }
}
$form.Controls.Count # 0
vfh0ocws

vfh0ocws2#

添加到Santiago's helpful answer

  • 事实上,问题是你的不受支持的尝试修改.RemoveByKey()一个集合$Form.Controls)*,而它正在被枚举 *。
    *通常情况下,应该报告 * 错误Collection was modified; enumeration operation may not execute. [1]
  • 在第一次调用.RemoveByKey()后,**你的管道 * 会安静地中止 *,这可能是一个 bug -请参阅GitHub issue #20181
  • 虽然有更好的解决方案-参见圣地亚哥的答案-但要使代码工作,所需的只是将$Form.Controls包含在@(...)中,数组子表达式运算符,它创建集合的 * 静态副本 *(作为[object[]]数组),然后将其枚举与$Form.Controls集合的修改隔离开来:
# Note the use of @(...)    
@($Form.Controls) | where { $array -contains $_.Name } | foreach { $Form.Controls.RemoveByKey($_.Name) }

[1]引发此错误的简单方法:$l = [System.Collections.Generic.List[string]] @('one', 'two'); foreach ($e in $l) { $l.Remove($e) }

相关问题