【问题标题】:Delete Panel within inside another panel删除另一个面板内的面板
【发布时间】:2020-10-01 07:39:34
【问题描述】:

我有一个面板,里面有 4 个面板。内部面板被命名为“XXXX | 1 | A”、“XXXX | 1 | B”、“XXXX | 1 | C”和“XXXX | 1 | D”,您可以看到它们在最后一个字符中的区别一封信。

在这种情况下,我要做的始终是只删除标识为 A 和 B 的面板。

这是我的代码。

Dim clickedLabel = DirectCast(DirectCast(DirectCast(sender, ToolStripMenuItem).Owner, ContextMenuStrip).SourceControl, Panel)

pb = clickedLabel.Parent
Dim controls_number As Integer = pb.Controls.Count
Dim spliterb
Dim con As Control

For Each con In pb.Controls

    spliterb = con.Name.Split("|")

    If spliterb(2).ToString = ("A") Or spliterb(2).ToString = ("B") Then
       pb.Controls.Remove(con)
    End If

Next

如你所见,通过变量controls_number我知道里面有4个Panel,但是在进行排列时,它只读取3,并且只删除了标识为B的Panel,没有到达Panel A。

您能向我解释一下您为什么不阅读 4 个面板吗?有什么想法可以让我完成所有 4 个?

谢谢。

【问题讨论】:

    标签: vb.net controls panel


    【解决方案1】:

    不要在使用For Each 循环枚举列表时修改列表。在这种情况和许多其他情况下,简单的解决方案是将您想要的项目提取到一个单独的列表中并循环遍历该列表,同时从原始列表中删除项目。因此,删除对您正在枚举的列表没有影响。在您的情况下,可能如下所示:

    Dim panels = pb.Controls.
                    OfType(Of Panel)().
                    Where(Function(pnl) pnl.Name.EndsWith("|A") OrElse
                                        pnl.Name.EndsWith("|B")).
                    ToArray()
    
    For Each pnl In panels
        pnl.Dispose()
    Next
    

    调用Dispose 将从其父级移除控件并正确处置它。如果您只是调用Remove,则不会释放控件。除非您打算重用该控件,否则这很糟糕。

    【讨论】:

    • 很好的答案,我正在应用你的答案。非常感谢您的时间和精力。
    • 要记住的一点是,首先将原始列表全部枚举,以便创建辅助列表,然后再枚举辅助列表。这确实使此选项的效率低于替代方案,但很少有人担心这种差异。您需要两个列表都非常大,否则要对大量列表执行此操作才重要。一般来说,编写简洁的代码应该是你的主要目标,如果这是一个真正的问题,你应该只特别关注性能。
    • 还有一个问题,在这种情况下如果我需要删除面板,因为我必须生成一个新的但具有其他属性,我看到正在使用 Dispose(),但它没有删除这样的对象,它只会重置,如果我尝试使用 Remove(),显然它会要求我提供控件部分,是否可以更改它?从列表中是的,虽然在这种情况下它总是 4,所以我认为没有问题。问候。
    • @LARC,它真的不知道你在说什么。无论如何都不会进行重置,也没有删除之类的事情。您可以从其父控件中删除该控件,并且可以释放该控件,这意味着释放其资源。无论如何,该对象仍然存在。关键是删除不会处理,但处理会删除。除非您想重用子控件,否则只需调用其Dispose 方法,否则在父Controls 集合上调用Remove,您可以稍后重新添加它们。
    【解决方案2】:

    首先,您不能使用管道字符“|”重命名控件因为设计师不允许。 但是在下面的示例中,我假设它是一个下划线字符“_”。 现在,当您循环一个集合时,如果它在此循环期间更改了她的维度,您将丢失新长度/维度之后的元素数量(您删除)。 因此,在这种情况下,您可以使用循环逆向(最大维度为 0)作为技巧,其余元素始终在循环内部/存在于循环中。

    下面这段代码说明了我的意思。

        For i As Integer = pb.Controls.Count - 1 To 0 Step -1
            If pb.Controls(i).Name Like "*_A" OrElse pb.Controls(i).Name Like "*_B" Then
                pb.Controls.Remove(pb.Controls(i))
            End If
        Next
    

    【讨论】:

    • 控件的Name 属性只是一个String,所以任何东西都是允许的。您不能在设计器中使用这样的名称,因为这也会导致使用相同名称声明字段并且标识符中不允许使用管道。但是,如果您在运行时创建控件,则没有相应的字段,因此对标识符的限制不适用。
    • 是的 @jmcilhinney 我的意思是设计师。我将把它添加为细节。 :)。上面的好方法。我喜欢它;)。
    • @G3nt_M3caj,您的回答简单明了,非常感谢您的时间和精力。
    • @G3nt_M3caj,还有一个问题,我尝试执行这两个条件,即A和B或C和D都可以被擦除,当我执行A和B时,它会这样做,但是当我执行 C 和 D 时,它会跳过它们,是否有任何不同的标准没有考虑到它们?
    • @LARC 只需在 if 子句中添加 Like "*_C" 或 Like "*_D"
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-15
    • 1970-01-01
    • 1970-01-01
    • 2017-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多