Я пытаюсь создать динамически созданную WinForm, в которую я передаю словарь имен (ключей) и URL-адрес, на котором размещено изображение (значения).
Код перебирает словарь и добавляет кнопку для каждой «клавиши», а когда кнопка нажата, он устанавливает изображение в поле изображения по URL-адресу для этой кнопки.
Каждый раз может быть разное количество кнопок (может быть до 10).
Я не знаю, правильный ли мой подход (ниже), но я получаю большую часть того, что хочу. Проблема в том, что изображение всегда только «Мейсон», независимо от того, какая кнопка нажата.
Add-Type -AssemblyName System.Windows.Forms
# Define a dictionary of names and image URLs
$image_url_lookup = @{
'Eric' = 'https://cdn.images.express.co.uk/img/dynamic/67/285x190/1758705_1.jpg'
'Mason' = 'https://cdn.images.express.co.uk/img/dynamic/67/285x190/1758732_1.jpg'
'Other' = 'https://cdn.images.express.co.uk/img/dynamic/67/285x190/1758699_1.jpg'
}
# Create a new form
$form = New-Object System.Windows.Forms.Form
$form.Text = "Select Images"
$form.Width = 800
$form.Height = 600
$form.BackColor = [System.Drawing.Color]::White
# Create a new table layout panel
$tableLayoutPanel = New-Object System.Windows.Forms.TableLayoutPanel
$tableLayoutPanel.Dock = [System.Windows.Forms.DockStyle]::Fill
# Create a new picture box
$pictureBox = New-Object System.Windows.Forms.PictureBox
$pictureBox.Width = $form.Width - 100
$pictureBox.Height = $form.Height - 100
$pictureBox.Left = ($form.Width - $pictureBox.Width) / 2
$pictureBox.Top = ($form.Height - $pictureBox.Height) / 2
$pictureBox.BackColor = [System.Drawing.Color]::Transparent
$pictureBox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::Zoom
$image_index = 0
foreach ($name in $image_url_lookup.Keys) {
$image_index++
$button = New-Object System.Windows.Forms.Button
$button.Name = "Button$image_index"
$button.Text = $name
$button.AccessibleName = $image_url_lookup[$name]
$button.Add_Click({ $pictureBox.ImageLocation = $button.AccessibleName })
$button.Width = 75
$button.Height = 23
# Add the button to the table layout panel
$tableLayoutPanel.Controls.Add($button, $i, 0)
}
# Add the picture box to the table layout panel
$tableLayoutPanel.Controls.Add($pictureBox, 0, 1)
$tableLayoutPanel.SetColumnSpan($pictureBox, $image_index + 5)
# Add the table layout panel to the form
$form.Controls.Add($tableLayoutPanel)
# Show the form
$form.ShowDialog() | Out-Null
$form.Dispose()
Мне не нравится TableLayoutPanel, и я предпочитаю использовать основную панель и добавлять массив дочерних панелей. Вы хотите, чтобы панель макета содержала 10 ячеек. Затем, чтобы получить доступ к каждой картинке, вам нужно получить доступ к каждой из 10 ячеек. Чтобы получить каждую ячейку, используйте следующее: learn.microsoft.com/en-us/dotnet/api/…
Вам нужно добавить вызов .GetNewClosure() в свой цикл, чтобы каждый блок скрипта помнил, что было $button.AccessibleName
, пока он был назначен, иначе произойдет то, что вы всегда получите значение последнего созданного $button
:
foreach ($name in $image_url_lookup.Keys) {
$image_index++
$button = [System.Windows.Forms.Button]@{
Name = "Button$image_index"
Text = $name
AccessibleName = $image_url_lookup[$name]
Width = 75
Height = 23
}
$button.Add_Click({ $pictureBox.ImageLocation = $button.AccessibleName }.GetNewClosure())
$tableLayoutPanel.Controls.Add($button, $i, 0)
}
Гораздо лучшим подходом было бы использование $this автоматической переменной в ваших событиях, таким образом, нет необходимости в новом закрытии; на это намекнул Тео в своем комментарии:
foreach ($name in $image_url_lookup.Keys) {
$image_index++
$button = [System.Windows.Forms.Button]@{
Name = "Button$image_index"
Text = $name
AccessibleName = $image_url_lookup[$name]
Width = 75
Height = 23
}
$button.Add_Click({ $pictureBox.ImageLocation = $this.AccessibleName })
$tableLayoutPanel.Controls.Add($button, $i, 0)
}
".. в своем комментарии" пожалуйста ;)
@ Тео попался, ты знаешь, как обстоят дела в наши дни, люди иногда обижаются :P
Да, я знаю.. То же самое происходит и в моей стране ;(
Попробуйте использовать свойство кнопок
Tag
для хранения URL, а неAccessiblename
. Это метка, которая кратко описывает и идентифицирует объект в своем контейнере, например текст в кнопке, имя элемента меню или метка, отображаемая рядом с элементом управления TextBox. Кроме того, внутри обработчика событий Click я бы использовал$this
для ссылки на сам объект кнопки. Нравится.. = $this.Tag