Embedding a form in a form

Ask questions about creating Graphical User Interfaces (GUI) in PowerShell and using WinForms controls.
Forum rules
Do not post any licensing information in this forum.

Any code longer than three lines should be added as code using the 'Select Code' dropdown menu or attached as a file.
User avatar
EnergySmithe
Posts: 9
Joined: Wed Jul 08, 2015 8:50 am

Embedding a form in a form

Post by EnergySmithe » Wed Oct 18, 2017 8:14 am

I would like to implement the equivalent of a tabbed MDI in Powershell Studio.

In C# I could approximate this by adding a tab to a tab control and adding the form to the controls collection in the new tab (with the form set to no border and dock set to fill, etc). Is there a way to accomplish the same thing with Powershell?

For example as a test in one of these child forms I tried setting this in the load event:

$global:MyChildForm = $main

And then in a parent form with a panel control tried this:

if((Show-ChildForm_psf) -eq 'OK')
{
$global:MyChildForm.TopLevel = $false
$global:MyChildForm.FormBorderStyle = 'None'
$global:MyChildForm.Dock = 'Fill'
$global:MyChildForm.Visible = $true
$panel1.Controls.Add($global:MyChildForm)
}

This actually does embed the form, but because of the ShowDialog() the functioning form shows up first, after that closes then the codebehind the buttons will no longer be functional because they have gone out of scope.

Hoping that with PS 5 class functionality something like this will now be possible? If I need to export the form and modify the return that is fine, but if there is a way to successfully do that at runtime, that would be preferable.

Any help or insights are much appreciated!

Powershell Studio 2017 5.4.145.0 64bit
Windows 7 64bit
Powershell v5.1.14409

Thanks

User avatar
davidc
Posts: 5913
Joined: Thu Aug 18, 2011 4:56 am

Re: Embedding a form in a form

Post by davidc » Wed Oct 18, 2017 9:32 am

There is some scoping and threading limitations within PowerShell that have prevented this in the past. With classes you might be able to do this, but we haven't tried yet it. The class would definitely resolve the scoping issue. You would also need to use the Show method instead of ShowDialog, which is Modal and locks up the process. To does this, you would have to modify the exported GUI script.
David
SAPIEN Technologies, Inc.

User avatar
davidc
Posts: 5913
Joined: Thu Aug 18, 2011 4:56 am

Re: Embedding a form in a form

Post by davidc » Thu Oct 19, 2017 9:33 am

I moved this topic to the PowerShell GUIs forum, so that our community experts could chime in.
David
SAPIEN Technologies, Inc.

User avatar
jvierra
Posts: 13682
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: Embedding a form in a form

Post by jvierra » Thu Oct 19, 2017 9:49 am

My first suggestion and easiest to build is to crate a custom controlset and add that to your form. You can show and hide this control set as needed and it can be designed to sync with the main form.

There is also a way to ahnd code a form that can be embedded in a parent form.

Why do you think you need a subform and what products have you seen this in? VB and VBA have had this capability for some time. Windows Forms really have no built-in method that supports subforms although third party controls can add this functionality.

User avatar
jvierra
Posts: 13682
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: Embedding a form in a form

Post by jvierra » Thu Oct 19, 2017 9:54 am

Here is an article describing how to do this with MDI.
MDI Forms

If this sounds OK I have a demo of an MDI in PowerShell Studio. As David noted, there are threading issues that limit what can be done but there are workarounds to may of the issues.

An MDI child is not really a subform. It is a "Child" form that can be located withtin the parent form and will minimize with the parent form.

User avatar
EnergySmithe
Posts: 9
Joined: Wed Jul 08, 2015 8:50 am

Re: Embedding a form in a form

Post by EnergySmithe » Thu Oct 19, 2017 10:47 am

jvierra and David, thank you both for your responses!

My underlying goal with this is to break out development of individual pieces of a single GUI tool, so that they can be worked on independently without having to re-integrate changes into a single project constantly.

MDI and child forms was a great way to accomplish that and would be awesome - however a key part of this is that the individual child forms need to be editable using the Designer, not hand writing them.

So If there is a way to take a standalone exported form and convert it to an MDI child in memory then that would fill this need perfectly!

Doing a subform was just a trick to try and get a tabbed MDI (like a browser, etc) but that could be accomplished other ways if MDI can be made to work.

I looked at controlsets, but I could not understand how to synchronize layout and code changes in a form where the controlset was defined with the forms where the controlset was being used. If there is a way to accomplish that, then I agree that would be a great solution as well!

For some reason the "MDI Forms" article link is not working for me, I will try doing a search to see if it comes up.

Again, thank you for your input on this!

User avatar
jvierra
Posts: 13682
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: Embedding a form in a form

Post by jvierra » Thu Oct 19, 2017 3:17 pm

What I have done is create a script that modifies the generated form script to remove the ShowDialog and return the form object. It also sets the parent form and does some other tweeks. If the form is simple and does not violate the rules of an MDI child then the launch is easy.

An update to PSS is not likely as it would require a new copy of the designer which is built to create child forms. Not impossible but also not trivial. I once set out to create a child designer as a Visual Studio add-in but dropped the project before it was completed. Starting with the PSS designer code would be easier but would still take a programmer a week to design build and fully test. Not a simple bug fix or basic enhancement.

The threading issues can be resolved using runspaces although I would just drop the capabilities that require a separate thread. It would also changing the main form to be launched with "Run" The issue is that the main form runs as a Dialog. Once a dialog access to the Windows message queue is limited.

Another way to do this is to launch a regular form in a separate runspace and have it the main MDI window. The issue with this is that it cannot be an MDI child and would require a sophisticated synchash to coordinate the two forms.

My ultimate solution was to use Visual Studio to build the form and events and host PowerShell to execute the scripts. This eliminates all issues with the form but requires that all scripts be able to run as hosted script. What I have done is to have the VS forms do all data entry and script selection then run an external script that returns objects which can be consumed by C#/Net forms. We also get highly advanced threading and task management with a compiled Net app. The downside is that PS scripters do not have the skillset needed to build Net forms so it requires a different development approach. One VS programmer and many scripters to build and test hosted scripts. I can build a form/child form in VS as fast as I can in PSS. The hard part is working out the design and interface to the scripts.

So you have many directions to go in - all with drawbacks. Isn't development always like that? I would choose to build a program that edits the PSS generated script to turn it into an MDI child.

User avatar
jvierra
Posts: 13682
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: Embedding a form in a form

Post by jvierra » Fri Oct 20, 2017 5:54 am

EnergySmithe wrote:
Thu Oct 19, 2017 10:47 am
I looked at controlsets, but I could not understand how to synchronize layout and code changes in a form where the controlset was defined with the forms where the controlset was being used. If there is a way to accomplish that, then I agree that would be a great solution as well!

For some reason the "MDI Forms" article link is not working for me, I will try doing a search to see if it comes up.
Here is a working link: viewtopic.php?f=21&t=10595&p=57549&hili ... rms#p57549

To mange and change embedded control sets just add a panel and size it as needed then add the control set to the panel at run time by clearing the controls collection on the panel and adding the new control set. Add the control sets as hidden controls and unhide after adding to the panel.

User avatar
EnergySmithe
Posts: 9
Joined: Wed Jul 08, 2015 8:50 am

Re: Embedding a form in a form

Post by EnergySmithe » Mon Oct 23, 2017 6:48 am

jvierra wrote:
Thu Oct 19, 2017 3:17 pm
So you have many directions to go in - all with drawbacks. Isn't development always like that? I would choose to build a program that edits the PSS generated script to turn it into an MDI child.
Wow thank you jvierra! I agree that writing a script to turn the generated form into an MDI would be the way to go. I tried playing with that idea by reading the form into a variable and do select string regex and replace to get the form function and change the return line to 'return $this'. But I am getting stuck on how to correctly call the modified code. If I use Invoke-Expression to call the form creation function contained in the variable and then run it, the scoping of the 'return $this' does not seem to be correct. Would you possibly be able to shed a little light on how you would approach that?

Thanks

User avatar
jvierra
Posts: 13682
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: Embedding a form in a form

Post by jvierra » Mon Oct 23, 2017 7:04 am

"$this" does not work with the form. You need to use the form variable name.

Code: Select all

		$f = Get-Item Function:\Show-Demo-DGVExport3_psf
		$txt = $f.Definition -replace 'return \$form1.ShowDialog\(\)', 'return $form1'
		$script:childForm = [System.Windows.Forms.Form]([scriptblock]::Create($txt).Invoke())[0]
		$script:childForm.MdiParent = $form1

Locked