By Roger Frost
The article MDI with C# by Irfan Patel is an excellent guide to
developing an MDI Application. I turned to this article for a quick
introduction to get my development up and running. I must say that Patel's
detailed step-by-step directions combined with his useful yet short
explanations make this article easy to read, follow and comprehend.
In less than 15 minutes of developing, I was pleased to see a full
implementation of an MDI application skeleton which I could easily build
on and use to test other UI concepts.
Like any newly created GUI, after compilation the next step is the
most obvious, start clicking and sliding controls. If Patel's steps were
followed verbatim, the average user will notice a problem very quickly.
After Opening and Closing the single instance form, the next attempt
to open this form will raise an error:
Cannot access a disposed object named "frmSChild".
Object name: "frmSChild".
To clarify, I have decided (and I assume) that a single instance form can be
opened more than once. "Single instance" simply means that only one form
may be open at any given time, and through the course of running the
program,
may need to be accessed more than once. Whereas "multiple instance" means
that as many forms as needed may be open concurently in the MDI Container.
The problem is with the method GetChildInstance() of the single
instance form (frmSChild). This method is required to ensure that this form
really is a single instance form. However, it only checks to see if the
form
hasn't been opened before, it does not check to see if it was previously
opened then disposed of. By changing:
if (m_SChildform ==null)
to:
if (m_SChildform ==null || m_SChildform.IsDisposed)
We can check for this second scenario. Now, a new frmSChild will be created
not only if it hasn't been created before, but aslo if the pervious instance
was closed.
It should be noted that this change will not cause the previous frmSChild
instance to be re-opened (ie. there is no such thing as Undispose()). The
instance being opened will be in the initial state as defined by the
frmSChild
class and/or other operations. However, the previous instance surendered all
of
it's resources at disposal to GC, and therefore this process will not
continue
to consume more and more resources if it is repeated time and time again.
This solution seems to be the most logical way to handle this problem to
me under most circumstances I face. On the other hand, what if in some
scenario
the single instance form is not to be disposed of everytime we remove it
from the
interface.
A minor change in frmMDIMain will allow the same instance of a single
instance form to be "opened" and "closed" throughout execution. The method
mnuFileCloseChild_Click() is responsible for closing the child which is
currently
active. If we change the line:
objfrmSChild.Close();
to:
objfrmSChild.Hide();
// Be sure the 'if' still uses the Close()
// method, the single instance is handled
// in 'else'
the form will remain in memory, yet will not be visible in the MDI
container.
This means that if both changes I have mentioned here were used, This change
has precedence over the previous, because m_SChildform.IsDisposed will
evaluate
to false unless frmSChild has been disposed of by some other event. Given
this,
even if this is the perfered solution to our problem, the previously
mentioned
change will serve as a safety net incase frmSChild does get disposed of by
some
other means (ie. in the future an operation is added to close frmSChild
elsewhere), and in my opinion would be considered good practice to include
at
any rate.
Now frmSChild can still be accessed progmatically, even when it is not
visible to the user, and all elements of the form remain even after it is
hidden.
Naturally, if the safety net is to be used as well, any information that was
assumed safe as a part of frmSChild will be lost on disposal, therefore may
prove
to be an unsafe net, especially in larger applications, and lead to logic
problems.