如何在 PowerShell 中为动态添加到 WinForm 的按钮创建单独的事件处理程序

huangapple go评论83阅读模式
英文:

How do I create individual event handlers for buttons added dynamically to a WinForm in Powershell

问题

我正在尝试创建一个动态生成的 WinForm,其中我传递一个包含名称(键)和图像托管的 URL(值)的字典。

代码会遍历字典并为每个“键”添加一个按钮,当按钮被按下时,它会将图片框设置为该按钮对应的 URL 上的图像。

每次都可能有不同数量的按钮(最多可能达到 10 个)。

我不确定我的方法是否正确,但我得到了我想要的大部分内容。问题在于,不管按下哪个按钮,图像始终是“Mason”。

  1. Add-Type -AssemblyName System.Windows.Forms
  2. # 定义名称和图像 URL 的字典
  3. $image_url_lookup = @{
  4. 'Eric' = 'https://cdn.images.express.co.uk/img/dynamic/67/285x190/1758705_1.jpg'
  5. 'Mason' = 'https://cdn.images.express.co.uk/img/dynamic/67/285x190/1758732_1.jpg'
  6. 'Other' = 'https://cdn.images.express.co.uk/img/dynamic/67/285x190/1758699_1.jpg'
  7. }
  8. # 创建一个新窗体
  9. $form = New-Object System.Windows.Forms.Form
  10. $form.Text = "Select Images"
  11. $form.Width = 800
  12. $form.Height = 600
  13. $form.BackColor = [System.Drawing.Color]::White
  14. # 创建一个新表格布局面板
  15. $tableLayoutPanel = New-Object System.Windows.Forms.TableLayoutPanel
  16. $tableLayoutPanel.Dock = [System.Windows.Forms.DockStyle]::Fill
  17. # 创建一个新图片框
  18. $pictureBox = New-Object System.Windows.Forms.PictureBox
  19. $pictureBox.Width = $form.Width - 100
  20. $pictureBox.Height = $form.Height - 100
  21. $pictureBox.Left = ($form.Width - $pictureBox.Width) / 2
  22. $pictureBox.Top = ($form.Height - $pictureBox.Height) / 2
  23. $pictureBox.BackColor = [System.Drawing.Color]::Transparent
  24. $pictureBox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::Zoom
  25. $image_index = 0
  26. foreach ($name in $image_url_lookup.Keys) {
  27. $image_index++
  28. $button = New-Object System.Windows.Forms.Button
  29. $button.Name = "Button$image_index"
  30. $button.Text = $name
  31. $button.AccessibleName = $image_url_lookup[$name]
  32. $button.Add_Click({ $pictureBox.ImageLocation = $button.AccessibleName })
  33. $button.Width = 75
  34. $button.Height = 23
  35. # 将按钮添加到表格布局面板
  36. $tableLayoutPanel.Controls.Add($button, $i, 0)
  37. }
  38. # 将图片框添加到表格布局面板
  39. $tableLayoutPanel.Controls.Add($pictureBox, 0, 1)
  40. $tableLayoutPanel.SetColumnSpan($pictureBox, $image_index + 5)
  41. # 将表格布局面板添加到窗体
  42. $form.Controls.Add($tableLayoutPanel)
  43. # 显示窗体
  44. $form.ShowDialog() | Out-Null
  45. $form.Dispose()

希望这对你有帮助。

英文:

I am trying to have a dynamically created WinForm where I pass in a dictionary of names (keys) and the url where the image is hosted (values).

The code, loops through the dictionary and adds a button for each 'key' and when the button is pressed, it sets the picturebox to be the image at the url for that button.

There can be a different number of buttons each time (maybe up to 10).

I don't know if my approach (below) is the right one but I get most of what I want. The problem is that the image is only ever 'Mason' no matter which button is pressed.

  1. Add-Type -AssemblyName System.Windows.Forms
  2. # Define a dictionary of names and image URLs
  3. $image_url_lookup = @{
  4. 'Eric' = 'https://cdn.images.express.co.uk/img/dynamic/67/285x190/1758705_1.jpg'
  5. 'Mason' = 'https://cdn.images.express.co.uk/img/dynamic/67/285x190/1758732_1.jpg'
  6. 'Other' = 'https://cdn.images.express.co.uk/img/dynamic/67/285x190/1758699_1.jpg'
  7. }
  8. # Create a new form
  9. $form = New-Object System.Windows.Forms.Form
  10. $form.Text = "Select Images"
  11. $form.Width = 800
  12. $form.Height = 600
  13. $form.BackColor = [System.Drawing.Color]::White
  14. # Create a new table layout panel
  15. $tableLayoutPanel = New-Object System.Windows.Forms.TableLayoutPanel
  16. $tableLayoutPanel.Dock = [System.Windows.Forms.DockStyle]::Fill
  17. # Create a new picture box
  18. $pictureBox = New-Object System.Windows.Forms.PictureBox
  19. $pictureBox.Width = $form.Width - 100
  20. $pictureBox.Height = $form.Height - 100
  21. $pictureBox.Left = ($form.Width - $pictureBox.Width) / 2
  22. $pictureBox.Top = ($form.Height - $pictureBox.Height) / 2
  23. $pictureBox.BackColor = [System.Drawing.Color]::Transparent
  24. $pictureBox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::Zoom
  25. $image_index = 0
  26. foreach ($name in $image_url_lookup.Keys) {
  27. $image_index++
  28. $button = New-Object System.Windows.Forms.Button
  29. $button.Name = "Button$image_index"
  30. $button.Text = $name
  31. $button.AccessibleName = $image_url_lookup[$name]
  32. $button.Add_Click({ $pictureBox.ImageLocation = $button.AccessibleName })
  33. $button.Width = 75
  34. $button.Height = 23
  35. # Add the button to the table layout panel
  36. $tableLayoutPanel.Controls.Add($button, $i, 0)
  37. }
  38. # Add the picture box to the table layout panel
  39. $tableLayoutPanel.Controls.Add($pictureBox, 0, 1)
  40. $tableLayoutPanel.SetColumnSpan($pictureBox, $image_index + 5)
  41. # Add the table layout panel to the form
  42. $form.Controls.Add($tableLayoutPanel)
  43. # Show the form
  44. $form.ShowDialog() | Out-Null
  45. $form.Dispose()

答案1

得分: 2

需要在循环中添加一个.GetNewClosure()调用,以便每个脚本块“记住”$button.AccessibleName在分配时的值,否则会发生的情况是,你总是获取到最后一个创建的$button的值:

  1. foreach ($name in $image_url_lookup.Keys) {
  2. $image_index++
  3. $button = [System.Windows.Forms.Button]@{
  4. Name = "Button$image_index"
  5. Text = $name
  6. AccessibleName = $image_url_lookup[$name]
  7. Width = 75
  8. Height = 23
  9. }
  10. $button.Add_Click({ $pictureBox.ImageLocation = $button.AccessibleName }.GetNewClosure())
  11. $tableLayoutPanel.Controls.Add($button, $i, 0)
  12. }

一个更好的方法是在事件中使用$this自动变量,这样就不需要新的闭包;这是由Theo在他的评论中提到的:

  1. foreach ($name in $image_url_lookup.Keys) {
  2. $image_index++
  3. $button = [System.Windows.Forms.Button]@{
  4. Name = "Button$image_index"
  5. Text = $name
  6. AccessibleName = $image_url_lookup[$name]
  7. Width = 75
  8. Height = 23
  9. }
  10. $button.Add_Click({ $pictureBox.ImageLocation = $this.AccessibleName })
  11. $tableLayoutPanel.Controls.Add($button, $i, 0)
  12. }
英文:

<!-- language-all: sh -->

You need to add a .GetNewClosure() call in your loop so that each scriptblock remembers what $button.AccessibleName was while it was assigned, otherwise what happens is that you're always getting the value of the last $button created:

  1. foreach ($name in $image_url_lookup.Keys) {
  2. $image_index++
  3. $button = [System.Windows.Forms.Button]@{
  4. Name = &quot;Button$image_index&quot;
  5. Text = $name
  6. AccessibleName = $image_url_lookup[$name]
  7. Width = 75
  8. Height = 23
  9. }
  10. $button.Add_Click({ $pictureBox.ImageLocation = $button.AccessibleName }.GetNewClosure())
  11. $tableLayoutPanel.Controls.Add($button, $i, 0)
  12. }

A much better approach would be to use the $this automatic variable in your events, that way there is no need for a new closure; this was hinted at by Theo in his comment:

  1. foreach ($name in $image_url_lookup.Keys) {
  2. $image_index++
  3. $button = [System.Windows.Forms.Button]@{
  4. Name = &quot;Button$image_index&quot;
  5. Text = $name
  6. AccessibleName = $image_url_lookup[$name]
  7. Width = 75
  8. Height = 23
  9. }
  10. $button.Add_Click({ $pictureBox.ImageLocation = $this.AccessibleName })
  11. $tableLayoutPanel.Controls.Add($button, $i, 0)
  12. }

huangapple
  • 本文由 发表于 2023年4月17日 03:49:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/76030010.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定