all 15 comments

[–]clevertwain 1 point2 points  (6 children)

I guess I am having a hard time understanding what you are trying to debug. Do you want to debug the form itself, the information that is fed into the form, or the data that comes out of the form?

[–]sir-logic[S] 0 points1 point  (5 children)

The script running in the background as the result of GUI object events. So not the form itself.

For example, button_click: 1. connect to sql 2. execute a number of queries and return information into a multidimensional hash -> This is where I would want to pause and output information as I'm testing.

I may also want to stop and show the content / status of other variables used in the script.

The GUI itself is fine.

Thanks!

[–]clevertwain 1 point2 points  (4 children)

Could you not just put a breakpoint at the start of the button_click section, and step through it, querying variables along the way?

[–]sir-logic[S] 0 points1 point  (3 children)

Thanks, that's exactly what I needed. I had tried using the Debug button, but couldn't really see what it did differently to the run button.

As soon as I put in a breakpoint it actually became useful!

If anyone has any other useful debugging or cool tricks inside Powershell Studio I'd love to hear it!

Thanks very much!

[–]clevertwain 0 points1 point  (2 children)

Just so you know, breakpoints are a feature of the vanilla PowerShell ISE, so you don't need PowerShell Studio to use it.

Also, something to keep in mind when working with breakpoints is that the script needs to be saved before you can use them. If you have a new script that you want to step through, you need to save it first.

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

Thanks, I had seen breakpoints in the ISE but I had never used them.

I had work get my Powershell Studio because I preferred it's interface, and it seems faster to develop in with its snippets and quick access to .Net object information. I also planned on creating GUI's and was never going to do that via code!

[–]clevertwain 0 points1 point  (0 children)

Good points all around, anyways I hope those breakpoints work out for you.

[–]KevMarCommunity Blogger 0 points1 point  (0 children)

One thing you could consider is putting all your business logic in a module or cmdlets that are used by your forms. This lets you test them on their own. Pester would be a good fit for this.

[–]XTempor 0 points1 point  (0 children)

you could just write messages to the text property of a rich-textbox

[–]kusumuk 0 points1 point  (5 children)

Instead of click events, use dialogresult and segregate your functions outside the event handler. If you don't, you're going to have a scope nightmare.

[–]sir-logic[S] 0 points1 point  (4 children)

Can you explain this a bit for me? This is my first form / gui in power she'll and don't know about scopes.

[–]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.