我在表单(144)上有很多需要删除的按钮。他们所有的名字都以“R”开头。所以我使用了这段代码。
Sub RemoveBookingButtons()
Dim cntrl As Control
For Each cntrl In Me.Controls
If Mid(cntrl.name, 1, 1) = "R" Then
Me.Controls.Remove(cntrl)
End If
Next
End Sub
但是,无论何时运行此子功能,它都会删除以“R”开头的所有其他按钮。有人可以建议更好的代码,或指出该代码中是否有缺陷,或者它隐藏在我程序中的其他地方。
答案 0 :(得分:2)
迭代期间不要更改Collection
。
您可以使用OfType
查找所有Buttons
:
Dim rButtons = Me.Controls.OfType(Of Button)().
Where(Function(btn) btn.Name.StartsWith("R")).ToList()
For Each btn In rButtons
Me.Controls.Remove(btn)
Next
澄清此代码:
一般情况下,这是LINQ-to-Objects。
Me.Controls.OfType(Of Button)()
这将返回表单ControlCollection
of Type Button
中的所有控件。
.Where(Function(btn) btn.Name.StartsWith("R"))
这会将结果集限制为Name
StartsWith
“R”的按钮(请注意,这是区分大小写的,如果希望它不区分大小写,则需要先调用ToLower/ToUpper
)。
.ToList()
这会从List(Of Button)
创建IEnumerable(OfButton)
。并不是任何LINQ查询都将被延迟执行。 Deferred execution表示表达式的评估被延迟,直到实际需要实现的值。因此,在任何消耗它之前,查询不会实现,在这种情况下,ToList()
执行它并创建列表。
答案 1 :(得分:0)
你正在修改你正在迭代的集合,所以它肯定会出错。我很惊讶它甚至跑了。
您应该将所有匹配的控件检索到一个新列表中,然后遍历该列表,从第一个列表中删除。
在C#中:
var toRemove = this.Controls.Where( ctrl => ctrl.Name.StartsWith("R") ).ToList();
foreach( var ctrl in toRemove )
{
this.Controls.Remove(ctrl);
}
在VB中:
dim toRemove = (from c in Me.Controls where c.StartsWith("R") select c).ToList()
for each ctrl in toRemove
Me.Controls.Remove(ctrl)
next
答案 2 :(得分:0)
解决问题的最小方法是使用For循环而不是For Each,
从控件集合的结尾开始,如
For i = Me.Controls.Count -1 To 0
Dim cntrl as Control = Me.Controls(i)
If Mid(cntrl.name, 1, 1) = "R" Then
Me.Controls.Remove(cntrl)
End If
Next