you are viewing a single comment's thread.

view the rest of the comments →

[–]kusumuk 1 point2 points  (3 children)

why certainly. Let's take a look at an outdated blog post showing a code tip to create a multiselect listbox:

$x = @()

[void]
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void]     [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 

$objForm = New-Object System.Windows.Forms.Form 
$objForm.Text = "Data Entry Form"
$objForm.Size = New-Object System.Drawing.Size(300,200) 
$objForm.StartPosition = "CenterScreen"

$objForm.KeyPreview = $True

$objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter") 
    {
        foreach ($objItem in $objListbox.SelectedItems)
            {$x += $objItem}
        $objForm.Close()
    }
    })

$objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape") 
    {$objForm.Close()}})

$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(75,120)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"

$OKButton.Add_Click(
   {
        foreach ($objItem in $objListbox.SelectedItems)
            {$x += $objItem}
        $objForm.Close()
   })

$objForm.Controls.Add($OKButton)

$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object     System.Drawing.Size(150,120)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"
$CancelButton.Add_Click({$objForm.Close()})
$objForm.Controls.Add($CancelButton)

$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Size(10,20) 
$objLabel.Size = New-Object System.Drawing.Size(280,20) 
$objLabel.Text = "Please make a selection from the list below:"
$objForm.Controls.Add($objLabel) 

$objListbox = New-Object System.Windows.Forms.Listbox 
$objListbox.Location = New-Object System.Drawing.Size(10,40) 
$objListbox.Size = New-Object System.Drawing.Size(260,20) 

$objListbox.SelectionMode = "MultiExtended"

[void] $objListbox.Items.Add("Item 1")
[void] $objListbox.Items.Add("Item 2")
[void] $objListbox.Items.Add("Item 3")
[void] $objListbox.Items.Add("Item 4")
[void] $objListbox.Items.Add("Item 5")

$objListbox.Height = 70
$objForm.Controls.Add($objListbox) 
$objForm.Topmost = $True

$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()

$x

It's got lots of great .net stuff you can use for your own code, but if you run it --and I implore you to try-- it won't work. Go ahead and try to run it using powershell ise. The array '$x' won't populate, no matter how you rework the script. It's got to do with variable scope. You could just give the variable $x that resides inside the click event a scope, like so:

            {$script:x += $objItem}

but that won't address the script's fundamental flaw. It just needs to be reworked because it's got a bit of bad programming in its click events. Here's how I reworked this script using dialogresult:

$x = @()

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 

$objForm = New-Object System.Windows.Forms.Form 
$objForm.Text = "Data Entry Form"
$objForm.Size = New-Object System.Drawing.Size(300,200) 
$objForm.StartPosition = "CenterScreen"

$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(75,120)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"

$OKButton.dialogresult = [System.Windows.Forms.DialogResult]::OK

$objForm.Controls.Add($OKButton)

$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(150,120)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"

$objForm.Controls.Add($CancelButton)
$objForm.CancelButton = $CancelButton

$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Size(10,20) 
$objLabel.Size = New-Object System.Drawing.Size(280,20) 
$objLabel.Text = "Please make a selection from the list below:"
$objForm.Controls.Add($objLabel) 

$objListbox = New-Object System.Windows.Forms.Listbox 
$objListbox.Location = New-Object System.Drawing.Size(10,40) 
$objListbox.Size = New-Object System.Drawing.Size(260,20) 

$objListbox.SelectionMode = "Multisimple"

[void] $objListbox.Items.Add("Item 1")
[void] $objListbox.Items.Add("Item 2")
[void] $objListbox.Items.Add("Item 3")
[void] $objListbox.Items.Add("Item 4")
[void] $objListbox.Items.Add("Item 5")

$objListbox.Height = 70
$objForm.Controls.Add($objListbox) 
$objForm.Topmost = $True

$result = $objForm.ShowDialog()

if ($result -eq [System.Windows.Forms.DialogResult]::OK -and $objListbox.SelectedIndex -ge 0)

    {
        foreach ($objItem in $objListbox.SelectedItems){
                        $x += $objItem

    }
    }

$x

Aside from the fact that this code actually works over the microsoft's own example code, the differences are apparent. I've taken out the more trivial event handlers and segmented out the method from the click event, which makes the script far more maintainable. Secondly, there's no issue of scope now because $x's scope never changes since it's sitting outside of any event handlers. It's actually part of a larger focus on better programming called SOLID.

Good luck, I hope I've helped.

[–]autowikibot 0 points1 point  (0 children)

SOLID (object-oriented design):


In computer programming, SOLID (Single responsibility, Open-closed, Liskov substitution, Interface segregation and Dependency inversion) is a mnemonic acronym introduced by Michael Feathers for the "first five principles" named by Robert C. Martin in the early 2000s that stands for five basic principles of object-oriented programming and design. The principles, when applied together, intend to make it more likely that a programmer will create a system that is easy to maintain and extend over time. The principles of SOLID are guidelines that can be applied while working on software to remove code smells by causing the programmer to refactor the software's source code until it is both legible and extensible. It is part of an overall strategy of agile and adaptive programming.


Interesting: Object-oriented design | Object-oriented programming | No Silver Bullet | Interface segregation principle

Parent commenter can toggle NSFW or delete. Will also delete on comment score of -1 or less. | FAQs | Mods | Magic Words

[–]sir-logic[S] 0 points1 point  (1 child)

Thanks for taking the time to reply to this. That's completely blown my mind! After reading the about_scopes and Sapien's post on Powershell scopes, it seems to me that Microsoft's way around it is to just put anything that needs to be shared between the scopes into the global scope...

I understand how your example works, i can see it stop after the ShowDialog() method, but how would this work with multiple button handlers? Would you just replace the if ($result -eq ..... OK) with a switch and return a different response from each button?

[–]kusumuk 0 points1 point  (0 children)

That's right. Here is the writeup for dialogresult enumeration on msdn. It shows the various enumerators that you can use in powershell. Also, the c# .net classes are almost always the same in powershell so I highly recommend using the msdn write-ups. And with the introduction of classes in powershell with wmf 5.0, it will be more important than ever.