User Rating: 5 / 5

Star ActiveStar ActiveStar ActiveStar ActiveStar Active
 
Tested on: PowerShell 2.0+, PowerShell Studio 2016

This step-by-step example shows you how to create a very simple multi-form PowerShell GUI app. The app consists of a parent form that gets data from a child form and displays it. When you finish, you'll know how to use the basic multi-form features of PowerShell Studio.

For details about how these features work under the covers, see How Do Multi-Form Projects Work? If you get stuck, the code for this project is on GitHub. If you prefer a video, see Create a Muiti-Form PowerShell GUI App (video).

In this blog, we assume that you know how to create a single-form PowerShell GUI app or that you've participated in a Thinking in Events hands-on lab. Otherwise, start with the My First Form videos (Part 1: Build a Simple PowerShell GUI App and Part 2: Controls and Properties) and read the beginner blogs in PowerShell GUIs: Where do I start?

---------------------

I had a great time in Austin, Texas (yes, Austin is still in Texas) last week with the Austin PowerShell User Group (@ATXPowerShell). Founded by Thom Schumacher and now admirably led by Aditi Satam, this awesome group serves PowerShell folks in the whole Austin metro area. And, Austin is home to whole slew of computing powers, including Facebook, Dell, IBM, AMD, 3M, and the famous University of Texas at Austin.

AustinAudience

 

This month, we were enjoying my Thinking in Events hands-on lab, where we build a PowerShell GUI and wrap it in an exe. This is a weird exercise for PowerShell folks who are used to linear programming of scripts that run in a console. (Learning to write GUI apps? PowerShell GUIs: Where do I start?)

The attendees asked terrific questions -- really insightful -- and we had a great time. A few of the questions were focused on the DialogResult property of forms and I realized that I didn't have a simple example of a multi-part form. So, here's one for my friends in Austin!

What's a Multi-Form App?

A multi-form or multi-page app is a GUI application with more than one window. It can be as simple as an app that launches a message box or as complex as a dozen-page wizard that collects a significant amount of data. But, to show you how to work with multiple forms, I want to start with a really simple example.

This little app starts with a main or parent form. When you click the Open Child Form button on the main form, the child form opens. When you type a message in the text box on the child form, and then click OK, the child form closes and the message that you typed appears in the text box on the main form.

The cool part of this exercise is not the functionality of the UI, which is quite limited. Instead, it's the conveniences that PowerShell studio adds, including wrapping forms in functions and making critical property values of the controls on each form easily accessible to the other form. (For an explanation of how these features work, see How Do Multi-Form Projects Work?)

 

In a form project with modal windows, one form opens another form. And, possibly another and another. The starting form is called the main form or parent form or owner, and window that's opened is called the child form. The child form can then open other forms, so it becomes the parent of another child form.

When you open a child form in a modal window structure, its parent form is temporarily disabled. We say that "control is passed to the child form." Then, when the child form closes, control is automatically passed to its parent form, which is reenabled. You do not need to add any code to reopen the parent form. Also, when you close the child form, the method that opened it (ShowDialog()) returns the DialogResult of the child form to the parent form. The DialogResult indicates which button was used to close the child form.

In addition, PowerShell Studio makes it really easy to open any form from any other form in the project by enclosing each form in a reference function that's available to all files in the project. To open the form, you just call its function. We'll see that feature at work in this simple project.

 

Step 1: Create a form project

Because we're working with multiple forms and, thus, multiple files, we'll start by creating a project. In PowerShell Studio, a project is a collection of related files. You can open and close them together and build tools from them, including PowerShell modules.

  • In PowerShell Studio, click File, New, New Form Project. Then, select Multi-Form Project, name the project, and click Create.

 

PowerShell Studio creates and opens four files:

  • MainForm.psf
  • ChildForm.psf
  • Globals.ps1
  • Startup.pss

 It also creates, but does not open, project files (.psproj, .psprojs) that help PowerShell Studio manage the project.

The Globals.ps1 file holds global variables and other values that are shared among the forms. Startup.pss lets you pass parameters to the application before it loads. We won’t be using these files in this task, so you can close them, but don’t delete them.

 

To reopen the project at any time, in PowerShell Studio, click File, Open Project (instead of Open).

For this GUI app, we'll start with the Child Form, which will be the information source, and then wire up the Main Form.

Set up the Child Form

The default child form is really simple. It comes with OK and Cancel buttons (both set to the appropriate DialogResult value). The script consists of an empty event handler for the form Load event. (The name of the variable that stores the Load event handler might vary. It depends on a template that PowerShell Studio uses and occasionally updates.)

 

 ChildForm Default

 

Start by changing the appearance, then work on the code. Make the following changes in the Properties pane.

  • Change the FormBorderStyle property of the form to FixedDialog (or any fixed value). No need to fuss with anchoring. I also delete the Cancel button because I'm not using it. You can leave it in. It does no harm.
  • Add a Label ($LabelSendMessage). Set its Text property to Send a message to Main Form.
  • Add a TextBox ($TextboxSendMessage). Set its Multiline property to True and enlarge it. Set its Font property to something more readable. I like Segoe UI 12.

 

Now, for the script.

In the Designer, double-click the Textbox to add the default event hander (TextChanged), and then add code to the Load and TextChanged event handlers to disable the OK button unless the textbox has some text (not just whitespace characters). We don't need any code in the OK button Click event handler ($buttonOK_Click), because its behavior is controlled by the DialogResult value.

 ChildForm code

 

That's all we need here. On to the Main Form.

Set up the Main Form

The default MainForm.psf comes with a Call Child Form button, but it's placed rather awkwardly in the middle of the window. Let's fix that.

To customize the appearance of main form for this app, make the following changes:

MainForm Finished

 

  • Change the FormBorderStyle property of the form to FixedDialog (or any fixed value). This is just a convenience.
  • Resize the button and the form. I like large buttons. Just a style preference.
  • Change the Text property of the button to Open Child Form. Call is a developer term that might not make sense to an end user.
    (When you change the Text property value, PowerShell Studio changes the name of the variable that holds the button to $buttonOpenChlldForm).
  • Add a Textbox ($textboxDisplayMessage). Set its Multiline and ReadOnly properties to $True and its Font property to Segoe UI 12.

Now, let's look at the script.

Opening Forms in a Form Project

As we discussed in What's a Multi-Form App?, PowerShell Studio encloses every form in a reference function. To open a form from another form or from a script in the project, call its reference function. The function name is arbitrary, but PowerShell Studio uses the following naming convention: 

Call-<FileName>_<Extension>

For example, PowerShell Studio adds the code in MainForm.psf to a Call-MainForm_psf function and the code in ChildForm.psf to a Call-ChildForm_psf function. To open the child form in ChildForm.psf, use the Call-ChildForm_psf function.

[TIP:  To see the reference functions, view the .ps1 file that PowerShell Studio generates for the project. In PowerShell Studio, click Deploy and then click Export to File.]

 

Before we change the script in the main form, let's examine the default code and make sure we understand it. The default MainForm.psf script includes an empty event handler for the Load event of the form, and a $buttonCallChildForm_Click event handler for the Click event of the $buttonCallChildForm button. 

MainForm Default

 

The $buttonCallChildForm_Click event handler default code is a bit abbreviated, because it's used often. Let's make sure we understand it. It does the following (in this order):

  1. It opens the child form by calling Call-ChildForm_psf, the reference function that contains the script for the child form.
  2. When the child form closes, it returns control to the main form. And, it returns a DialogResult value that indicates which button (on the child form) was clicked to close the form.
  3. If the child form was closed by clicking the OK button (or any button that returns a DialogResult value of OK), it runs the code in the script block, which is empty by default. If the form is closed by clicking a button that returns a different DialogResult value, such as Cancel, the code in the (empty) script block doesn't run.

Let's customize it. This is the fun part.

 

Getting Values from Controls in Other Forms

We already have the Call-ChildForm_psf function that opens the child form when you click the now renamed Open Child Form button ($buttonOpenChildForm). Let's add the code that gets the text from the textbox in the child form ($textboxSendMessage) and displays it in the read-only textbox ($textboxDisplayMessage) in the parent form.

Here's how to do it. Yes, I know. Pretty cool, eh?

 ReturnValue

 

In a multi-form project, PowerShell Studio creates script-scoped variables that contain the values of selected properties of the most frequently used Windows Forms controls. We call these return variables. (For an explanation of how these features work, see How Do Multi-Form Projects Work?)

When you add a call to a reference function (the function that contains the code for a different form in the same project), PowerShell Studio makes the return variables from the called form automatically available to your file and to any file in the project that calls the form.

In this script, because MainForm.psf calls Call-ChildForm_psf, PowerShell Studio adds a $ChildForm_textboxSendMessage variable that contains the Text property of the $textboxSendMessage Textbox in ChildForm.psf. That makes it really easy to assign the value to the $textboxDisplayMessage in the main form.

Be sure to avoid the 'gotcha'. $ChildForm_textboxSendMessage already contains the Text property of the textbox, so don't try to get its Text property

$textboxDisplayMessage.Text = $ChildForm_textboxSendMessage      #Right
$textboxDisplayMessage.Text = $ChildForm_textboxSendMessage.Text #Wrong

The #Wrong one doesn't work, because $ChildForm_textboxSendMessage contains the Text property of the Textbox, which is a string. Because strings don't have a Text property, $ChildForm_textboxSendMessage.Text returns $null. I know this because I've done it. More than once.

 

Final tweaks

Everything is working well in this little GUI app. I just added a few tweaks to make it more user-friendly.

Because the user can open the child form and type a message repeatedly, each time I display the parent form, I want the $textboxDisplayMessage to be blank. So, in MainForm.psf, in the $buttonOpenChildForm_Click event handler, call the Clear method to erase any text from the previous call. This is the same as setting the Text property of the textbox to $null or an empty string ('') or even [System.String].Empty. Use any technique that works for you.

$buttonOpenChildForm_Click ={ 

    $textBoxDisplayMessage.Clear()   # Clears form between tries

    if ( (Call-ChildForm) -eq 'OK' ) 
    { 
        $textboxDisplayMessage.Text = $ChildForm_textboxSendMessage 
    }
}

 

Also, by default, the child form opens on top of the main form. This makes it hard to see the display text box on the main form.

Superimposed

So, in the Properties pane, I change the values of the StartPosition property of each form, so the child form opens next to the main form, not on top of it.

Form

Default StartPosition

New StartPosition

MainForm

CenterScreen

WindowsDefaultLocation

ChildForm

CenterParent

CenterScreen

 

Finished app

 

That's a pretty simple multi-form application, but it shows you how to use reference functions to call one form from another and how to use the return variables that PowerShell Studio creates to make PowerShell GUI development as easy as possible. Now that you know the fundamentals, you're ready for even more complex and adventurous multi-form PowerShell GUI apps.

Need the code for this project? It's on GitHub.

June Blender is a technology evangelist at SAPIEN Technologies, Inc. and a Windows PowerShell MVP. You can reach her at This email address is being protected from spambots. You need JavaScript enabled to view it. or follow her on Twitter at @juneb_get_help.

If you have questions about our products, please post in our support forum.
For licensed customers, use the forum associated with your product in our Product Support Forums for Registered Customers.
For users of trial versions, please post in our Trial Software Questions forum.
Copyright © 2017 SAPIEN Technologies, Inc.