• Powershell forms which button?

    Home » Forums » Developers, developers, developers » DevOps Lounge » Powershell forms which button?

    Author
    Topic
    #490705

    Hey Y’all,

    In my continuing quest to learn powershell I’ve come across a problem I can’t seem to get past.

    The following code shows a dialog box of available drive letters. It works fine except in one condition.
    If the user selects a drive then presses the cancel button the function still returns the selected drive.
    I’ve tried and tried but can’t come up with a solution to tell which button was pressed. If I get a return value from the show form command it shows “cancel” for either button! :angry:

    Code:
    
    Function DriveList() {
    
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 
    
    $Pushed = ""
    $drives = Get-PSDrive -PSProvider FileSystem
    
    $objForm = New-Object System.Windows.Forms.Form 
    $objForm.Text = "Drive Selection"
    $objForm.Size = New-Object System.Drawing.Size(300,200) 
    $objForm.StartPosition = "CenterScreen"
    
    $objForm.KeyPreview = $True
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter") 
        {$ExtDrive=$objListBox.SelectedItem;$objForm.hide()}})
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape") 
        {$objForm.hide()}})
    
    $OKButton = New-Object System.Windows.Forms.Button
    $OKButton.Location = New-Object System.Drawing.Size(10,120)
    $OKButton.Size = New-Object System.Drawing.Size(75,23)
    $OKButton.Text = "OK"
    $OKButton.Add_Click({$objForm.hide()})
    
    
    $CancelButton = New-Object System.Windows.Forms.Button
    $CancelButton.Location = New-Object System.Drawing.Size(95,120)
    $CancelButton.Size = New-Object System.Drawing.Size(75,23)
    $CancelButton.Text = "Cancel"
    $CancelButton.Add_Click({$objForm.hide()})
    
    
    $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 select a drive:"
    
    $objListBox = New-Object System.Windows.Forms.ListBox 
    $objListBox.Location = New-Object System.Drawing.Size(10,40) 
    $objListBox.Size = New-Object System.Drawing.Size(160,20) 
    $objListBox.Height = 80
    
    for( $curDrive = 0; $curdrive -lt $drives.Count; $curDrive++)
    {
        [void] $objListBox.Items.Add($drives[$curDrive].Name)
    }
    
    $drives = Get-PSDrive -PSProvider FileSystem
    
    $objForm.Controls.AddRange(@($OKButton,$CancelButton,$objLabel,$objListBox))
    $objForm.Topmost = $True
    
    [void] $objForm.ShowDialog()
    
    $ExtDrive = $objlistbox.SelectedItem
    $ExtDrive  #Return selected drive
    $objForm.dispose()
    
    }   # End Function DriveList
    
    # Test code to call function:
    
      $ExtDrive = DriveList   #Call Function
    #  $ExtDrive += ":" #Note: This line NOT needed if only letter is required
    
      write-host "The selected drive is: $ExtDrive"
    

    It’s probably simple but I sure can’t figure it out. :cheers:

    May the Forces of good computing be with you!

    RG

    PowerShell & VBA Rule!
    Computer Specs

    Viewing 8 reply threads
    Author
    Replies
    • #1409686

      The problem is that the code is not checking the results of the $objForm.ShowDialog() function call. This function returns information about which button the user clicked to terminate the dialog. Only if the user clicked OK should the code read and act on the contents of the dialog. See the description of the ShowDialog function at: http://msdn.microsoft.com/en-us/library/c7ykbedk.aspx

      Essentially, each part of the dialog is its own object that keeps track of its own state, so the list of drives keeps track of what drive was select at the time the selection was made. If you could somehow monitor that list while the dialog is showing (you can do this in most debuggers), and made several different selections in the list you would see the list’s value change with each selection. Thus regardless of which button is clicked to terminate the dialog, all of the input fields in the dialog can be accessed afterwards to determine their values; but the code should react to the contents only if OK is returned by ShowDialog.

    • #1409723

      Cafed00d,

      That looked promising but…

      System.Windows.Forms.DialogResult.OK : The term
      ‘System.Windows.Forms.DialogResult.OK’ is not recognized as the name of a
      cmdlet, function, script file, or operable program. Check the spelling of the
      name, or if a path was included, verify that the path is correct and try again.
      At line:25 char:20
      + $OKButton.result = System.Windows.Forms.DialogResult.OK
      + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      + CategoryInfo : ObjectNotFound: (System.Windows.Forms.DialogResult.OK:String) [], CommandNotFoundException
      + FullyQualifiedErrorId : CommandNotFoundException

      PowerShell doesn’t seem to like it. :cheers:

      May the Forces of good computing be with you!

      RG

      PowerShell & VBA Rule!
      Computer Specs

    • #1409873

      Accessing an enumeration value is Powershell is a little tricky, the correct syntax is: [System.Windows.Forms.DialogResult]::OK
      Weird, huh?

      But before you can use this toi check the form result, you need to tell the form and the buttons what they are used for.
      First, replace this line:

      [INDENT]$OKButton.Add_Click({$objForm.hide()})[/INDENT]

      with these two lines:

      [INDENT]$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
      $objForm.AcceptButton = $OKButton[/INDENT]

      This code registers $OKButton as the accept button on the form (invoking the accept button automatically closes the form so you don’t need a separate on-click method), and also sets what the form result will be when the button is invoked.
      Similarly, for the cancel button replace this line:

      [INDENT]$CancelButton.Add_Click({$objForm.hide()})[/INDENT]

      with these lines:

      [INDENT]$CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
      $objForm.CancelButton = $CancelButton[/INDENT]

      Now you are set to check the result from the dialog box. Replace these lines:

      [INDENT][void] $objForm.ShowDialog()

      $ExtDrive = $objlistbox.SelectedItem
      $ExtDrive #Return selected drive[/INDENT]

      with these lines:

      [INDENT]$dialogResult = $objForm.ShowDialog()
      if ($dialogResult -eq [System.Windows.Forms.DialogResult]::OK)
      {
      $ExtDrive = $objlistbox.SelectedItem
      $ExtDrive #Return selected drive
      }[/INDENT]

      That’s it. The DriveList function now returns a value only when OK is clicked.

    • #1409920

      Cafed00d,

      Works like a charm, thanks so much. I googled & googled and never ran across any example like that! Of course it could have been I was using the wrong terms but I’ve found that most of the stuff you find for PS is very elementary especially when it comes to using Windows Forms.

      Thanks Again :thewave: :cheers:

      For those who might be interested here’s the full working code.

      Code:
      Function DriveList() {
      
      [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
      [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 
      
      $Pushed = ""
      $drives = Get-PSDrive -PSProvider FileSystem
      
      $objForm = New-Object System.Windows.Forms.Form 
      $objForm.Text = "Drive Selection"
      $objForm.Size = New-Object System.Drawing.Size(300,200) 
      $objForm.StartPosition = "CenterScreen"
      
      $objForm.KeyPreview = $True
      $objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter") 
          {$ExtDrive=$objListBox.SelectedItem;$objForm.hide()}})
      $objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape") 
          {$objForm.hide()}})
      $objForm.AcceptButton = $OKButton
      $objForm.CancelButton = $CancelButton
      
      $OKButton = New-Object System.Windows.Forms.Button
      $OKButton.Location = New-Object System.Drawing.Size(10,120)
      $OKButton.Size = New-Object System.Drawing.Size(75,23)
      $OKButton.Text = "OK"
      $OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
      
      $CancelButton = New-Object System.Windows.Forms.Button
      $CancelButton.Location = New-Object System.Drawing.Size(95,120)
      $CancelButton.Size = New-Object System.Drawing.Size(75,23)
      $CancelButton.Text = "Cancel"
      $CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
      
      
      $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 select a drive:"
      
      $objListBox = New-Object System.Windows.Forms.ListBox 
      $objListBox.Location = New-Object System.Drawing.Size(10,40) 
      $objListBox.Size = New-Object System.Drawing.Size(160,20) 
      $objListBox.Height = 80
      
      for( $curDrive = 0; $curdrive -lt $drives.Count; $curDrive++)
      {
          [void] $objListBox.Items.Add($drives[$curDrive].Name)
      }
      
      $drives = Get-PSDrive -PSProvider FileSystem
      
      $objForm.Controls.AddRange(@($OKButton,$CancelButton,$objLabel,$objListBox))
      $objForm.Topmost = $True
      
      $dialogResult = $objForm.ShowDialog()
      
      if ($dialogResult -eq [System.Windows.Forms.DialogResult]::OK)
      {
      $ExtDrive = $objlistbox.SelectedItem
      $ExtDrive #Return selected drive
      }
      $objForm.dispose()
      
      }   # End Function DriveList
      
      # Test code to call function:
      
        $ExtDrive = DriveList   #Call Function
      #  $ExtDrive += ":" #Note: This line NOT needed if only letter is required
      
        write-host "The selected drive is: $ExtDrive"
      

      May the Forces of good computing be with you!

      RG

      PowerShell & VBA Rule!
      Computer Specs

    • #1410267

      It is difficult to find examples on how to construct forms because no one builds forms by hand. Visual Studio has an excellent visual forms editor. You drag and drop buttons and other widgets onto a background, tweak some property values, and Visual Studio does all the grunt work to write the code to build the form. The great thing is, you can actually look at that code. If you plan to do a lot of form building, I strongly suggest that you get a copy of Visual Studio for C# – that one will build a source file closest to what you want. The Visual Studio 2012 Express version is free. And there are a lot of tutorials that show how to build forms using Visual Studio. And you can even find out how to code some of the more esoteric widgets.

    • #1410367

      cafed00d,

      Thanks for the tip I’ll give it a try. :cheers:

      May the Forces of good computing be with you!

      RG

      PowerShell & VBA Rule!
      Computer Specs

    • #1410432

      Hi RetiredGeek,

      I see from your signature that you like VBA. Have you ever heard of the AutoIt scripting language? Many people (myself included) believe it’s much easier to learn and use than PowerShell. Many consider it to be the modern replacement to the old VB 6 (and other versions prior to the more complicated .NET update to the VB language).

      AutoIt (home page) is a freeware BASIC-like scripting language designed for automating the Windows GUI and general scripting. AutoIt scripts can be compiled into an executable that can be run on any modern Windows operating system (including Windows Server operating systems). And, it has a feature that VB 6 and most other programming languages don’t have – the ability to include any number of desired files (images, INI files, DLLs, EXEs, etc.) within the same compressed executable to be extracted (as required) at run-time and then to either leave the extra files there or remove them. You can learn a lot about AutoIt and what it can do by reading this overview of AutoIt from the AutoIt web site. There is a very active world-wide community via the AutoIt Forums to help with questions, I’ve used the forums on a several occasions and the community is very responsive and helpful. There’s even an AutoIt Wikipedia page.

      There is also an AutoIt Wiki with lots of good information. Of particular interest will be the Tutorials page.

      If you’re interested, I can share more info – or just navigate the URLs that I’ve already provided.

      Happy coding! 🙂

    • #1410434

      Techie,

      Yes I’ve heard of Autolt. I may give it a look but my real motivation right now is learning PowerShell just because I want to. It’s nice to be retired! 😆 :cheers:

      May the Forces of good computing be with you!

      RG

      PowerShell & VBA Rule!
      Computer Specs

    • #1410457

      Well, already having knowledge of the VBA language, I think you’d like the AutoIt language syntax better (at least it would come more naturally to you) and it’s faster than PowerShell (without the overhead of the .NET Framework). And, you can make your own GUI/Forms using one of a few free GUI/Forms Designers – one of them is even an entire AutoIt IDE (Integrated Development Environment) developed using AutoIt! (Or you can just using develop your GUIs in code like the long-timers do :cool:). It has built-in functions to allow you to interact with any kind of GUI object (Windows, buttons, fields, etc.), whether your app, another app or those of Windows itself. The community has also developed some very good User Defined Functions (called UDFs) that assist in automating Word, Excel, Outlook, IE, and many more! There’s really so much more that AutoIt can do, it really is very impressive!

      I started out on the task to learn PowerShell for my job, but I’ve switched to learning (and using) AutoIt more and more in my job (and at home).

      The very active AutoIt community includes some very knowledgeable developers (they know more about development than I do) and they are there to assist others to learn more about programming using AutoIt.

    Viewing 8 reply threads
    Reply To: Powershell forms which button?

    You can use BBCodes to format your content.
    Your account can't use all available BBCodes, they will be stripped before saving.

    Your information: