1

下面的“for each”循环只运行一次。为什么?

该项目包含 4 个表格。Form1 包含 4 个 PictureBox。我正在尝试遍历表单列表(在此示例中,将每个表单的 BG 设置为图片框):

Sub Butt_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Butt.Click
    Dim Forms As New List(Of Form)
    Dim Pics As New Dictionary(Of Form, PictureBox)
    Forms.Add(me)
    Forms.Add(form2)
    Forms.Add(form3)
    Forms.Add(form4)

只执行第一次迭代:

    For Each frm As Form In Forms
        pics(frm) = Me.Controls("PictureBox" + CStr(i + 1))(0)
        'BTW the next line behave the same:
        '  pics(frm) = CType(Me.Controls("PictureBox" + CStr(i + 1)), PictureBox)
        'or this:
        '  pics(frm) = PictureBox1
        'or if the pics is a dictionary(of string):
        '  pics(frm.name) = PictureBox1
    Next

执行所有 4 次迭代:

    For Each frm As Form In Forms
        msgbox(frm.name)
    Next

为什么它不会在第一个循环中进行所有 4 次迭代?

编辑:

“我”不是问题。显然问题在于将相同的控件分配两次,作为“图片”字典的值......仍在调查中。

编辑 2 - 中间摘要

工作解决方案(但不是答案)

For x As Integer = 0 To Forms.Count - 1
    pics(Forms(x)) = DirectCast(PictureBox1, PictureBox)
Next

你的答案可以分为

1. 字典语法:dict.add(k, v) vs. dict(k) = v

2. exceotion monster按照一些人的建议吃掉我的异常。

3. 正如@Andre Pageot 所建议的,需要施放巫术

4. VB 不喜欢将同一个图片框两次添加到字典中。

(1.) 可能不是问题。语法dict(k) = v 适用于其他任何地方。我什至尝试过 dict.add(k,v) 并且它给出了完全相同的行为,即仍然错误。

(2.) IDE 确实有问题:调试器跳过“Next”语句,并照常继续循环后的下一条指令。(WTF) 即使在我设置为在 Alt+Ctrl+E 屏幕中捕获所有异常之后也没关系。仍然没有捕获到异常。

恕我直言,这是一个严重的错误,即使 redmond 的某个人是故意设计的。同样的“有趣的行为”可能是从 VB6 时代继承下来的,有时代码会无缘无故地“飞走”。(但至少在那里它正在退出应用程序)。

ps 我没有任何“try-catch”子句,也没有“错误时做一些愚蠢的事情”,只是为了清楚:)

(3.) 可能是它,虽然我不明白,但它没有回答这个问题——“为什么原始代码在运行时会做 weewooo”。

请参阅上面的“工作解决方案”。

坦率地说,我不想再理解它了,因为它让我发疯,为什么,在 Python 中,我只写 dict(k) = y 并且它永远不会中断。我不明白 dict.contains(k,v) 是如何可能的。它没有任何意义。而且必须有感觉,它是在编程,而不是巫术。

(4.) 我没有任何方法(或意愿)来证明它。

感谢你们。

在这个项目之后,我可能永远不会再使用 VB 了。有这么多巫毒的事情要处理,不值得头疼。

4

3 回答 3

3

因为这部分:

pics(frm)

大概是Nothing。我在这里猜测是因为我没有抛出异常。

你永远达不到Next 声明。这就是为什么你只有一次迭代。
您的错误正在其他地方被吞没。尝试在 Exceptions 面板中激活Common Language Runtime ExceptionsThrown属性。( ctrl+ alt+ e)。


也许你应该尝试更换

pics(frm)

经过

pics.Add(frm, Me.Controls("PictureBox" + CStr(i + 1))(0))

于 2013-05-16T15:55:20.790 回答
2

我似乎记得遇到过类似的问题,如果记忆有用,诀窍是客观地从 for each 中删除表格,就像这样

Sub Butt_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles     Butt.Click
Dim Forms As New List(Of Form)
Dim Pics As New Dictionary(Of Form, PictureBox)
Forms.Add(me)
Forms.Add(form2)
Forms.Add(form3)
Forms.Add(form4)

For x As Integer = 0 To Forms.Count - 1
    If Not Pics.Contains(Forms(x), DirectCast(Me.Controls("PictureBox" + CStr(i + 1))(0), PictureBox)) Then
            Pics.Add(Forms(x), DirectCast(Me.Controls("PictureBox" + CStr(i + 1))(0), PictureBox))
        Else
            Pics(Forms(x)) = DirectCast(Me.Controls("PictureBox" + CStr(i + 1))(0), PictureBox)
        End If
Next

################################################# ###################################### 更新探索并扩展上述内容### ################################################# #########################

下面是对这个问题的更详细的解释和分解,以及为什么它实际上不是 .NET 中的神话或怪事

.NET OO 框架非常庞大复杂且功能强大,要理解和记住这一切并非人为不可能,但需要掌握一些概念才能在迷宫中导航。

让我们检查一下出了什么问题。

您用项目中的每个表单声明并填充了表单列表 List(Of Form)

Dim Forms as New List(Of Form)

然后,您声明了一个字典来保存形状(Form、PictureBox)的(键、值)集合

Dim Pics as New Dictionary(Of Form, PictureBox)

这意味着您的“Key”是 Form 类型,而您的“Value”是 PictureBox 类型

现在,使用您正在遍历列表中每个表单的表单列表,说您希望将Dictionary*(Pics)* 中“键” (表单)的“值” (图片框)设置为图片框在名称为“PictureBox(x)”的当前表单(代码正在运行的位置)上找到,其中 x 是某种增量整数值。奇怪的是,您然后要求该图片框的第一个实例(那是最后的 (0) 部分)

For Each frm As Form In Forms
    pics(frm) = Me.Controls("PictureBox" + CStr(i + 1))(0)
Next

从根本上说,从 pics(frm) 调用的方法仅获取或设置字典中现有项目的值,因为字典尚未加载任何内容,Pics 是空的,您从未向字典中添加任何表单因此,根本不会设置任何内容。

实现键值分配的更合适的方法如下,但是简单地设置表单的背景图像仍然是矫枉过正的

Sub BuildDictionary()
    '1. Declare the array of forms and the dictionary of (Key,Values) of type (Form,PictureBox)
    Dim Forms As New List(Of Form) 'list of forms that you want to assign BG
    Dim Pics As New Dictionary(Of Form, PictureBox) 'declare your dictionary list ("Key","Value") = (Form,Picturebox)
    With Forms 'fill the list
        .Add(Me)
        .Add(Form1)
        .Add(Form2)
        .Add(Form3)
    End With

    '2. Snag the picturebox we want to assign to the forms
    Dim PictureBoxToAssign As PictureBox = DirectCast(Me.Controls("PictureBox" + CStr(i + 1)), PictureBox) 'grab your picturebox

    '3 option 1 (prefered)
    '#### Either Do this next
    Pics.Clear() 'if your logic allows that you can clear the dictionary first
    For x As Integer = 0 To Forms.Count - 1 'for each form in the array
        Pics.Add(Forms(x), PictureBoxToAssign) 'add the form and picturebox to the dictionary            
    Next

    '3 option 2 (only if you cannot clear the dictionary)
    '#### Or Do this
    'you cannot clear the dictionary first due to logic
    For x As Integer = 0 To Forms.Count - 1 'for each form in the array
        'check existance of the pair
        If Pics.Contains(New Generic.KeyValuePair(Of Form, PictureBox)(Forms(x), PictureBoxToAssign)) Then
            Pics(Forms(x)) = PictureBoxToAssign 'update the value 
        Else
            Pics.Add(Forms(x), PictureBoxToAssign) 'add the new pair
        End If
    Next
End Sub

如果目标只是将每个表单的背景图像设置为图片框的图像,那么可能更快更有效的路线可能是以下示例

Sub SetBG()
    Dim Forms As Form() = {Me, Form1, Form2, Form3} 'array of forms that you want to assign BG, occupies less memory than a list
    Dim PictureBoxToAssign As PictureBox = DirectCast(Me.Controls("PictureBox" + CStr(i + 1)), PictureBox) 'grab your picturebox
    For x As Integer = 0 To Forms.Count - 1 'for each form in the array
        Forms(x).BackgroundImage = PictureBoxToAssign.Image 'assign the image to the background      
    Next
End Sub

这里要记住的重要一点是,当以任何方式更改对象时,在遍历数组中的对象集合时,虽然可能,但不能使用“将每个 obj 作为对象数组中的类型”的方法来完成,即不像这样

For Each obj as ObjectType in ArrayofObjects
    Change the properties of obj = (BIG NO CAN DO)
Next

必须将循环与直接与集合中的对象交互分开,在本示例中,通过使用 for each 像这样的索引

For x As Integer = 0 To Forms.Count - 1 'using an integer not the object itself
    'referencing the object through the index of the collection Forms(x)
    Forms(x).BackgroundImage = PictureBoxToAssign.Image 
Next

我希望这个答案能给黑暗带来光明

于 2013-05-16T17:16:47.277 回答
0

分配给您的 Pics 字典的代码在我看来是错误的。要将新项目添加到字典中,您不能只分配给该索引。您必须使用 .Add() 方法。

当您尝试分配给尚不存在的键时,应引发异常。这可以通过您的循环解释一次。你第一次进入循环,抛出异常,所以你的代码永远不会到达第二次迭代。如果你在某个地方吞下了那个例外,你永远不会知道。

Sub Butt_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Butt.Click
    Dim Forms As New List(Of Form)
    Dim Pics As New Dictionary(Of Form, PictureBox)
    Forms.Add(me)
    Forms.Add(form2)
    Forms.Add(form3)
    Forms.Add(form4)

    For Each frm As Form In Forms
        pics.Add(frm, Me.Controls("PictureBox" + CStr(i + 1))(0))
    Next
于 2013-05-16T16:00:19.233 回答