How Do Multi-Form Projects Work?
- Details
- Written by June Blender
- Last Updated: 23 September 2022
- Created: 18 July 2016
- Hits: 41381
This article was written in 2016 (PowerShell Studio 2016, Windows PowerShell 3.0+). The instructions in this article were updated in September 2022.
I recently wrote an article with step-by-step instructions for creating a very simple multi-form PowerShell GUI application. In our sample app, we use PowerShell Studio features that make it very easy to open a child form from the main form and get the text in the textbox on the child form.
You can find the code for this project on GitHub. For a video of the app-building instructions, see Create a Muiti-Form PowerShell GUI App (video).
In this article, I'll explain what goes on in the background to make these features work. You might not care -- just so they work -- and that's fine. But if you're wondering how this happens, or you need to debug a problem, or you'd like to customize these features for your environment, this information will help.
It's One Script
One of the first things to know about GUI apps is that PowerShell Studio combines the code in the form or form project -- all of it -- into a single PowerShell script, a .PS1 file. This GUI app script includes the code you write in your .psf files and the code that PowerShell Studio generates for you to make the GUI app work properly. This organization has a particular benefit in multi-form projects, because it makes it easy to share values among the forms, including variables.
When you create a PowerShell Studio multi-form project, you start with Globals.ps1, Startup.pss, MainForm.psf, and ChildForm.psf files. If you add forms to the project, PowerShell Studio creates each form in a separate .psf file.
But, when you run or debug the form or project, PowerShell Studio combines the code in all of those files into a single .ps1 script file. It's that script file-- created in memory -- that runs when you click Run or Debug. It's also the script that is packaged into an executable file (.exe) or a Microsoft installer file (.ms1) when you use the Package or Installer features of PowerShell Studio.
- To generate an exported file copy of the GUI app script, in PowerShell Studio, click Deploy / Export to File. The default file name is <ProjectName>.Export.ps1.
(Or, click Export to Clipboard, and then paste the contents into your favorite text editor, such as Notepad.)
IMPORTANT: Do not edit the *.Export.ps1 copy of the GUI app script while your work is in progress. It is an output file, not an input file, and your changes will be overwritten. To change the script in the project, edit the project files. When your project is complete, you can generate the .Export.ps1 and use it as your main project file. At that point, you can edit it, too.
NOTES:
- PowerShell Studio creates a .ps1 script for single-form projects, too. To see it, click Deploy / Export to File (or Export to Clipboard).
- The <Project>.Export.ps1 script is not automatically updated when the scripts in the project change. PowerShell Studio uses an in-memory copy of the script.
- When you open <Project>.Export.ps1 file in PowerShell Studio, it asks two questions:
- Do you want to load the source file? (If YES, it runs the .psproj file, which opens the project and project files.) Answer: No.
- Do you want to regenerate the source files? (If you've lost your .psf files, you can recreates them from your .ps1.) Answer: No.
What's in the GUI App Script?
The form script is really a fascinating file and it's worth taking some time to examine it. It's all PowerShell, so you can understand it and use the code in your scripts.
It includes:
- The commands that load the assemblies you use in the System.Windows.Forms namespace.
- The New-Object commands that create the WinForm control objects, such as Form, Textbox, and Button, and save them in variables.
- The commands that set the properties of the objects, like the Textbox, and register the object events. Here's where PowerShell Studio uses the values that you set in the Properties pane.
- And, of course, the code in your .psf file.
It also includes commands to set up and clean up your app so you don't encounter failures and timeouts particular to GUI applications. It includes the call to the ShowDialog() method that opens the child form as a modal window and returms the DialogResult value. And, it includes functions that contain the code in your form files. Let's look at that next.
The Forms are Functions: Reference Functions
In the GUI app script, the contents of each .psf file is enclosed in a reference function. The reference functions let you open and run the forms they define by calling the function name, just as you would any other function.
PowerShell Studio names these reference functions Show-<FileName_<Extension>. For example, the code in MainForm.psf is enclosed in the Show-MainForm_psf function. And the code in ChildForm.psf is enclosed in a Show-ChildForm_psf function. (This was changed in 2017 from the previous reference function names using "call". Example: Call-ChildForm_psf.)
The reference functions make it very easy to open a form from another form. For example, this form project has MainForm.psf, ChildForm.psf, and KidForm.psf files. Each form in the project can call the reference functions for all other forms. No dot-sourcing is required, because all of the functions are in the same script.
With reference functions, opening another form in a project is as easy as calling the reference function. For example, this Click event handler opens the child form defined in ChildForm.psf. You don't need to create any custom code.
$buttonOpenChildForm_Click {
Show-ChildForm_psf
}
But, what if you want access to data collected by the child form?
Control Properties are Return Variables
It's so common for a parent form to collect data from a child form that PowerShell Studio has special features to support it.
For example, a main form opens a child form that includes a MonthCalendar control. When the user selects a date and clicks the OK button on the child form, control returns to the main form, along with a DialogResult value of OK. Then the event handler in the main form responds to the selected start date. This is a pretty common case.
But, how, in the main form, do you get the date that the user selected (its SelectionStart property value) in the MonthCalendar control in the child form?
$buttonOpenChildForm_Click {
$DialogResult = Show-ChildForm_psf
if ($DialogResult -eq 'OK')
{
$dateSelected = # Get selected date from child form
switch ($dateSelected.Year)
{
2017 {...}
2016 {...}
{2000..2015 -contains $_} {...}
default {...}
}
}
}
In PowerShell Studio, it's easy! When you add the reference function for the child form (Show-ChildForm_psf) to the MainForm.psf script, PowerShell Studio makes the values of selected control properties of the child form available to the main form. The return variable name format is $<FileName_VariableName>. For example, the value of the SelectionStart property of $monthcalendarEmployeeDate in ChildForm.psf becomes $ChildForm_monthcalendarEmployeeDate in all other files in the project.
This isn't magic, of course, it's just PowerShell. In the GUI app script, PowerShell Studio creates a script-scoped variable that can be read (and written to) by all functions in the script. In this case, it creates $script:ChildForm_monthcalendarEmployeeDate. You can find it in the GUI app script,
In your .psf files, you can refer to these script-scoped variables by name or with the $script: prefix. For example:
$ChildForm_monthcalendarEmployeeDate
-or-
$script:ChildForm_monthcalendarEmployeeDate
PowerShell Studio Return Variables
PowerShell Studio needs to be agile, so it doesn't create script-scoped variables for all properties of all controls in all child forms. It just creates them for the most frequently used property of the most frequently used controls.
This table lists the supported controls and properties.
Control Property Type Help Resource CheckBox Checked System.Boolean Spotlight on the Checkbox Control CheckedListBox SelectedItems System.Windows.Forms.ListBox.SelectedObjectCollection ListBox.SelectedItem ComboBox Text and SelectedItem System.String Spotlight on the ComboBox Control DateTimePicker Value System.DateTime DateTimePicker.Value ListBox SelectedItems System.Windows.Forms.ListBox.SelectedObjectCollection ListBox.SelectedItems ListView SelectedItems System.Windows.Forms.ListView.SelectedListViewItemCollection Spotlight on the ListView Control MonthCalendar SelectionStart System.DateTime MonthCalendar.SelectionStart NumericUpDown Value System.Decimal MonthCalendar.SelectionStart RadioButton Checked System.Boolean Spotlight on the RadioButton Control RichTextBox Text System.String RichTextBox.Text TextBox Text System.String Spotlight on the TextBox Control TreeView SelectedNode.Text System.String TreeNode.Text
But, be careful! Remember the type of the value that the variable stores. For example, the $ChildForm_monthcalenarEmployeeDate variable already contains the SelectionStart property value, which is a DateTime object. If you try to its the SelectionStart property, the DateTime object doesn't have one, and the result is $null.
$date = $ChildForm_monthcalendarEmployeeDate.SelectionStart # Wrong
$date = $ChildForm_monthcalendarEmployeeDate # Right
Create Custom Return Variables
If you need a different property value from a child form, just create a script-scoped variable in the child form. For example, if you want the label text from the child form to be available to other forms in the project, create a script-scoped variable in the ChildForm. To make it obvious, I like to create the variable in the form Load event and then set its value in the event handler for the value change.
Just like the script-scoped variables that PowerShell Studio creates, your script-scoped variables are available to other forms in the project.
So, that's how it works behind the scenes. You don't need to know this, but understand how it works makes me more confident when I use the features and it helps when I need to debug them.
To see the features in action, see Write a Multi-Form PowerShell GUI App. You can also get the code, including the *.Export.ps1 file 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.