Write a Multi-Form PowerShell GUI App
- Details
- Written by June Blender
- Last Updated: 22 September 2022
- Created: 15 July 2016
- Hits: 75731
This article was written in 2016 (PowerShell 2016, PowerShell 2.0+). The instructions in this article were updated in September 2022.
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.
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, Project, then double-click Multi-Form Project:
- A pop-up will open prompting for additional project information. Give the project a name, then 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.)
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.
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:
- 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:
Show-<FileName>_<Extension>
For example, PowerShell Studio adds the code in MainForm.psf to a Show-MainForm_psf function and the code in ChildForm.psf to a Show-ChildForm_psf function. To open the child form in ChildForm.psf, use the Show-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.
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):
- It opens the child form by calling Show-ChildForm_psf, the reference function that contains the script for the child form.
- 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.
- 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 Show-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?
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 ( (Show-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.
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 |
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.
You can follow June Blender (Windows PowerShell MVP) on Twitter at @juneb_get_help.
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 Former and Future Customers - Questions forum.