Friday, August 04, 2006

A Family of Forms

Occasionally you might want to make a form the child of another, or the child of a control. In VB6 you were pretty much limited to using an MDI parent form or the Win32 API to parent windows. In .NET, you now have another choice.

Without resorting to Win32 API's, you can make a form the child of another form or control in two ways.

The Controls Collection
Since System.Windows.Forms.Form inherits from System.Windows.Forms.Control, each form is in fact a control. The Control class exposes a Controls property, which is a collection of it's child controls. Since a form is a control, you can add a form to the Controls collection of any other control. For example, say you had Form1 containing a panel control called Panel1, and you wanted to make Form2 the child of Panel1, you could achieve this with the following code;

Form2 f2 = new Form2();
f2.TopLevel = false;
Panel1.Controls.Add(f2);

It's important to note the following line;

f2.TopLevel = false;

If you try to make a top-level form a child of another form or control you'll get an exception thrown. By explicitly setting the child forms TopLevel property to false before adding it to the controls collection, you'll avoid the error.

Unfortunately, that's not the end of the story though. Once you've made your form a child, it's behaviour will change slightly. Certain events, such as the Activate and Deactivate events won't fire, and you may experience problems with other features such as KeyPreview. In effect, if you're making an existing form (or a form that inherits from a specialised form class) a child, you'll need to test it thoroughly as a child window to ensure it hasn't lost any functionality.

Using this technique is the only 'managed' way you can make a form the child of a control (rather than another form), and it has the benefit of working with both controls and forms.

MDI Windows
You can also create parent/child relationships between Forms using the MDI properties of the Form class. To create the parent form, set it's MdiContainer property to true. To create a child, set it's MdiParent property to the parent form's reference. For example, the following code would make Form2 the MDI child of Form1;

this.IsMdiContainer = true;

Form2 f2 = new Form2();
f2.MdiParent = this;
f2.Show();

This method isn't without it's problems though. Firstly it appears that MDI children are always drawn with the FixedSingle form border style when they are initially displayed, regardless of the property setting on the form in question. The window is then redrawn using the correct style, so you might not notice this symptom unless the PC is slow or under load when the window is displayed.

The second problem is you may still find some events don't fire exactly the same way as they used to when the form wasn't an MDI child.

Finally, you may also encounter a Win32Exception with the message Error creating window handle. If you search the web you'll find a number of possible causes for this, including;

However, I am currently having this problem in one of my applications and it isn't explained by any of the above causes. I haven't yet been able to diagnose the reason for this behaviour.

So, while you have a couple of ways to parent controls and forms, be careful about how you choose to do so and be sure to test your code well.

No comments:

Post a Comment