2013-05-16 4 views
1

Следующий цикл «для каждого» выполняется только один раз. Зачем?vb.net «Для каждого» повторяется только один раз над списком

Проект содержит 4 формы. Form1 содержит 4 PictureBox. Я пытаюсь перебирать список форм (в данном примере, чтобы установить BG каждой формы на PictureBox):

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 итерации в первом цикле?

Edit:

"я" не является проблемой. Очевидно, проблема заключается в том, что дважды назначается один и тот же элемент управления, как значение для словаря «pics» ... все еще исследуется.

Edit 2 - промежуточное резюме

рабочий раствор (но не ответ)

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

Ваши ответы могут быть сгруппированы в синтаксисе

1. Словарь: dict.add (к , v) vs. dict (k) = v

2. exceotion монстр ест мое исключение, как это предложено некоторыми.

3. литье вуду необходимости, как это было предложено @Andre Pageot

4. VB не хотел бы добавить один и тот же PictureBox дважды в словарь.

(1.), вероятно, не является проблемой. Синтаксис dict (k) = v работает везде. Я даже попробовал dict.add (k, v), и он дал EXCATLY такое же поведение, то есть все еще ошибку.

(2.) В среде IDE действительно что-то не так: отладчик пропускает оператор «Следующий» и продолжает, как обычно, следующую инструкцию после цикла. (WTF) Это не имело значения даже после того, как я решил уловить все исключения на экране Alt + Ctrl + E. Исключение все еще не обнаружено.

Это ИМХО серьезная ошибка, даже если кто-то из redmond сделал это по дизайну. Такое же «забавное поведение», вероятно, унаследовано от дней VB6, иногда код «улетал» без всякой причины. (Но, по крайней мере, он отказался от приложения).

p.s. У меня нет каких-либо предложений «try-catch», а «ошибка не делает что-то глупое», просто чтобы быть ясным :)

(3.) Возможно, это, хотя я не понимаю, и это не так. «Ответ на вопрос -« почему исходный код делает weewooo во время выполнения ».

См. Выше «рабочий раствор».

FRANKLY Я НЕ ХОТИМ, ЧТОБЫ ПОНИМАТЬ ЭТО, ПОТОМУ ЧТО ЭТО ДВИЖИТ МЕНЯ, ЧТО, В ПИТОНЕ, Я ТОЛЬКО ПИСЬМАЮТ dict (k) = y И НИКОГДА НЕ БЕРЕТ. Я НЕ ПОНИМАЮ, КАК ЕГО ВОЗМОЖНО, чтобы dict.contains (k, v). ЭТО НЕ ДЕЛАЕТ ЛЮБОЙ СМЫСЛ. И ЭТО ДОЛЖНО БЫТЬ СОВЕРШЕННО, ЭТО ПРОГРАММИРОВАНИЕ, а не вуду.

(4.) У меня нет способа (или будет), чтобы это доказать.

Спасибо, ребята.

Я, вероятно, никогда не буду использовать VB после этого проекта. Есть так много вещей вуду, с которыми нужно иметь дело, это не стоит головных болей.

+1

Где находится 'i' и вы его увеличиваете? – jonhopkins

+1

Вы не увеличиваете 'i' после ссылки на изображение, это ошибка или вы увеличиваете это в другом месте? – bendataclear

+0

Почему это имеет значение (в отношении ВОПРОСА, а не логики)?Я добавил пример (commented), где нет «i». –

ответ

2

Кажется, я помню, работает в подобной проблеме, трюк, если память служит, чтобы удалить форму объективно от для каждого, как так

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 

######## ################################################## ################################# UPDATE исследуют и расширяют вышеуказанное ########### ################################################## #################

Что f ollows является более подробным объяснением и нарушением этой проблемы и почему это на самом деле не миф или странность в .NET.

The.NET OO-структура невероятно сложна и мощна, чтобы понять и запомнить, что все это невозможно по-человечески, но есть несколько концепций, которые нужно понять, чтобы пробраться через лабиринт.

Давайте рассмотрим, что случилось.

Вы объявили и заселена список форм списка (форма) с каждой формой в проекте

Dim Forms as New List(Of Form) 

Затем объявил словарь для хранения коллекции (ключ, значение) в форме (Форма, PictureBox)

Dim Pics as New Dictionary(Of Form, PictureBox) 

Это означает, что ваш "ключ" имеет тип формы и ваш "Value" имеет тип PictureBox

Теперь, используя список форм, вы повторяли каждую форму в списке, заявив, что хотите «Значение» (PictureBox) «Ключ» (Форма) в словаре * (Pics) * to быть установленным в PictureBox, найденном в текущей форме (где код запущен) с именем «PictureBox (x)», где x - ваше инкрементное целочисленное значение какого-либо типа. Как ни странно вы затем просить первый экземпляр чего-то, что PictureBox (то будет (0) часть на конце)

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

Фундаментально метод вызывается из фотографии (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 

Если цель просто установить фон изображение каждой формы к образу PictureBox, то, возможно, быстрее, более эффективный путь может быть следующим примером

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 

важно Реме mber здесь заключается в том, что при любом изменении объекта, в то время как итерация через коллекцию объектов внутри массива, по возможности, НЕ должна выполняться с использованием подхода «для каждого объекта obj как тип в массиве объектов», то есть не так, как это

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

вам MUST отделить цикл от прямого взаимодействия с объектом в коллекции, в этом примере, используя для каждого индекса, как так

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 

Я надеюсь, что этот ответ приносит свет к темноте

+0

Я действительно не понимаю ничего из этого, но это вроде как сработало. Посмотрите мое последнее Редактирование в исходном вопросе. –

2

Из этой части:

pics(frm) 

Это, вероятно, Nothing. Я угадываю здесь, потому что у меня нет выброшенного экскремента.

Вы никогда не достигаете заявления Next. Вот почему у вас есть только одна итерация.
Ваша ошибка проглатывается где-то в другом месте. Попробуйте активировать Исключения для обычного языка Runtime's Thrown property in the Exceptions pannel. (ctrl + al + e).


Может быть, вы должны попробовать заменить

pics(frm)

по

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

+0

Скорее «ничего», как это VB.NET;) –

+0

@MattWilko My C# плохой habbits ^.^Спасибо. – phadaphunk

+0

К сожалению, таинственное исключение все еще не поймано даже после установки ВСЕХ исключений, которые нужно обработать (даже после того, как я перезапустил VS, просто чтобы убедиться) –

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 
+0

Что значит? Я делаю это все время. Согласно MSDN (http://msdn.microsoft.com/en-us/library/9tee9ht2.aspx), «операция set создает новый элемент с указанным ключом». –

+0

downvote: синтаксис SAME используется во втором цикле, где он работает. –

Смежные вопросы