MDI Help

I

info

I am trying to create an MDI Application. I am opening the windows OK
(MDI Children). But I don't think I am doing it correctly.

Basically, I declare the forms on the main form (Parent).

frm1 f1;
frm2 f2;

etc

One for each form.

Then, when I open the form, I just do:

if (f1 != null)
f1 = new frm1;
....
f1.Show();
f1.BringToFront();

However, if I close the form, and try open... it breaks... I have no
code for the close, so it seems to think that even though f1 is
closed... it's not null...

How should I be closing forms? Or, is there a better way to be doing
this?
 
M

Marc Gravell

even though f1 is closed... it's not null...

Yes - nothing will automatically clear fields, so it *isn't* null (nor
is it collected, since the field keeps it in-scope).

Two solutions; the first is the hook into the Form's FromCosed event
and set the field to null - but this is a little scrappy since it
makes having multiples of a form tricky. Personally I'd forget about
the fields, and simply enumerate the MdiChildren looking for a likely
form - if you find such, bring it to the front, else spawn a new one
and add it as a child. This way, you don't have to worry about the
fields (there aren't any). And you can probably do the "show existing/
new form<x>" simply with generics - something like (notepad code - not
tested):

void ShowForm<T>() where T : Form, new() {
foreach(Form child in MdiChildren) {
if(child is T) {
child.BringToFront();
return;
}
// not found
T newForm = new T();
newForm.MdiParent = this; // or however... I can't remember...
newForm.Show();
newForm.BringToFront();
}
}

Marc
 
M

Marc Gravell

Forgot to add - then you would just call:

ShowForm<Form1>();

or whatever, where Form1 is the class-name of a type of Form.
 
I

info

Forgot to add - then you would just call:

ShowForm<Form1>();

or whatever, where Form1 is the class-name of a type of Form.

Fantastic!
I'll give this a bash. I'm quite a novice at this. Thanks for the
help, Marc.
 
I

info

Darn.. battling...

Should my ShowForm function look something like this?

private void ShowForm(Form form)
{
foreach (Form child in MdiChildren)
{
if (child is form)
{
child.BringToFront();
return;
}
}
// not found
form newForm = new form();
newForm.MdiParent = this;
newForm.Show();
newForm.BringToFront();
}
 
M

Marc Gravell

Not if you intend it to work the way I did... the generics (the <T>
stuff) was important to this solution (let me know if you are using
1.1, since generics don't exist there); you'd need as below (and I've
tested it this time):

Marc

private void ShowForm<T>() where T : Form, new()
{
foreach (Form child in MdiChildren)
{
if (child is T)
{
child.BringToFront();
return;
}
}
// not found
T newForm = new T();
newForm.MdiParent = this;
newForm.Show();
newForm.BringToFront();
}

then call i.e. "ShowForm<Form1>();"
 
M

Marc Gravell

aside: I've just realised that my tested and working code was exactly
what I posted earlier (untested); if you had some problems with
getting this to work, then please let me know.

Marc
 
I

info

aside: I've just realised that my tested and working code was exactly
what I posted earlier (untested); if you had some problems with
getting this to work, then please let me know.

Marc

Sorry Marc, didn't realise I must include the 'where T : Form, new()'
part. This is syntax I have never seen before. Was a bit confusing.
Will read up on 'generics' to help me work out what's happening there?

Will try this code you sent.

Thanks kindly.
 
M

Marc Gravell

Will read up on 'generics'
(MSDN: http://msdn2.microsoft.com/en-us/library/512aeb7t.aspx)

Generics are the "big feature" in 2.0, in the same way (but much, much
more so) as LINQ is the "big feature" in 3.5. It is a big (and very
important) area, so I can't attempt to do it much justice, but in
short, the code says:

* ShowForm is a generic method that accepts a single "type parameter"
named (by convention) "T" [this is the <T> bit]
* The caller is only allowed to invoke ShowForm with types that derive
from Form (inclusive) [T : Form()], and which have a public
parameterless constructor [T : new()]

When the method is called, "T" is a template (a Type); broadly
speaking, if you call it with Form1 as the type parameter (by saying
ShowForm<Form1>()), then imagine doing a find-and-replace inside
ShowForm on "T" replaced with "Form1":
.... if(child is Form1) ...
.... Form1 newForm = new Form1();
etc

The big restriction is that you can only use members that *must* exist
for *any* template - i.e. the methods on System.Object, and anything
that are constraints [T : Form, new()] introduce. For instance, we can
only use newForm.MdiParent because the compiler knows that it is (at
minimum) a Form, and Form has an MdiParent.
(this is different to C++ templates, where-by it checks at compile
time for suitable members; .NET generics are actually runtime-based
(not compile-time), so must work for types the compiler doesn't yet
know about).

This also means you can't call the method with unsuitable type
arguments, i.e. ShowForm<StringBuilder> will fail at compile-time
because StringBuilder isn't a Form.

There is quite a lot more depth to generics (compile-time type-
parameter-inference, for example) - but a fascinating area, and one
that you are going to have to face at some point to work with .NET 2
(and above).

Perhaps the first generics example people see is List<T> - i.e.
List<int> data = new List<int>();
data.Add(16);
....
data.Add(13);
data.Sort();
[etc; same things, but this time a whole generic type, not just a
generic method]

Marc
 
I

info

It's working, but I haven't quite grasped the workings behind it.
Also, when I close the mdiChild form, is it freed, or do I need code
to make sure it's dead. I ask, as when I close it, and reopen.. the
new form seems to appear in a lower position... as if it was
cascading, even though the other form has been closed. Is this normal?
 
M

Marc Gravell

Also, when I close the mdiChild form, is it freed, or do I need code
to make sure it's dead.
Yes, it should be fully disposed and available for garbage collection.
I ask, as when I close it, and reopen.. the
new form seems to appear in a lower position... as if it was
cascading, even though the other form has been closed. Is this
normal?
This is normal for a new form; if you want it to appear in the same
position as it (or rather: the previous form) was, then you'll either
need to save the location/size somewhere, else simply hide the old
form (proabably by catching the "closing" event, set the cancel flag,
and call Hide() instead)

Marc
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top