#vb.net #winforms #lambda
#vb.net #winforms #лямбда
Вопрос:
Используя приведенную ниже функцию, серия кнопок генерируется в панель компоновки потока на основе существующего XML-документа. Функция вызывается при загрузке программы и успешно генерирует кнопки с разными атрибутами, пока на них не нажмут. При нажатии на кнопки они должны выводить свои атрибуты на панель просмотра таблицы данных, но она вводит только атрибуты последнего узла в XML-документе.
Function loadMenuItems() As Double
m_xmld = New XmlDocument
m_xmld.Load("Menu.xml")
m_nodelist = m_xmld.GetElementsByTagName("menuItems")
For Each m_node In m_nodelist
Dim newButton As New Button
strID = m_node.Item("ID").InnerText
strName = m_node.Item("Name").InnerText
strPrice = m_node.Item("Price").InnerText
strOptions = m_node.Item("Options").InnerText
newButton.Name = "BTN_" amp; strID
newButton.Width = 150
newButton.Height = 150
newButton.BackgroundImageLayout = ImageLayout.Zoom
newButton.TextImageRelation = TextImageRelation.TextAboveImage
newButton.ForeColor = Color.White
newButton.Text = strName
AddHandler newButton.Click, Sub()
DGV_Receipt.Rows.Add(strName, strOptions, strPrice)
End Sub
newButton.BackgroundImage = Image.FromFile(".ResourcesIcons" amp; strName amp; ".png")
FLP_Icons.Controls.Add(newButton)
Next
End Function 'end the function definition.
Загружаемая функция:
Private Sub FORM_Main_Load(sender As Object, e As EventArgs) Handles MyBase.Load
loadMenuItems()
End Sub
Я новичок в VB, поэтому, если я упускаю что-то очевидное, пожалуйста, дайте мне знать!
Комментарии:
1. Думаю, ваша проблема связана с тем, как вы извлекаете strName, strOptions и strPrice в AddHandler. Эти значения будут перезаписываться в вашем цикле. Думаю, вам нужно будет хранить их по-другому. Либо в виде расширенных свойств кнопки (возможно, достаточно закодировать каким-либо образом в теге), либо сохранить эти значения в отдельной коллекции, которую вы можете просматривать на основе того, какая кнопка была нажата
2. В качестве альтернативы ответу, я думаю, это сработало бы, если бы вы либо объявили три строковые переменные внутри цикла (чтобы каждый раз замыкание захватывало другую переменную), либо, возможно, если вы не используете переменные, а вместо этого используете ссылку на внутренний текст xml (я думаю, что более поздние версии .NET будут повторно создавать переменную итерации при каждом прохождении через цикл, чтобы вы не получали неожиданных результатов при ее захвате).
Ответ №1:
Как было предложено в комментариях, проблема заключается в вашем обработчике событий. В том, как работают лямбда-выражения, есть некоторый нюанс, и вы сталкиваетесь с этим.
Одним из вариантов было бы сохранить правильные данные в Tag
свойстве, которое является полем данных общего назначения, каждого Button
, например
newButton.Tag = {strName, strOptions, strPrice}
а затем получите данные обратно из Button
в обработчике событий:
AddHandler newButton.Click, Sub(sender, e)
Dim btn = DirectCast(sender, Button)
Dim data = DirectCast(btn.Tag, String())
DGV_Receipt.Rows.Add(data(0), data(1), data(2))
End Sub
В качестве альтернативы, определите свой собственный пользовательский класс, который наследует Button
, добавьте специальные свойства для этих значений, а затем используйте их в своем коде. Этот пользовательский класс будет работать так же, как обычный Button
но вы можете установить эти свойства при его создании, а затем получить данные из них обратно в обработчике событий.
Комментарии:
1. Да, имеет смысл сохранить эти значения в свойстве тега, однако, когда я попытался реализовать ваш код, мне пришлось заменить
sender
наnewButton
.