No offense, but this seems to be a very convoluted solution to a problem that was solved a very long time ago.
You shouldn't be doing anything in the Dispose() method other than disposing other disposables (and even then only if the disposing flag is true.) So I would not modify the method that the designer generates for you.
So the immediate answer to your question as to why this is happening is almost certainly related to the timing of the garbage collector calling your Dispose method.
Instead you should probably consider using a MDI (multiple document interface) parent form and your "sub forms" are called MDI children. You could then handle the FormClosing event in the children like so.
(Note that if you are opposed to MDI, you can do basically the same thing by using form Owners.)
// MDI child
private void Form_FormClosing(object sender, FormClosingEventArgs e) {
if (e.CloseReason == CloseReason.UserClosing) {
e.Cancel = true;
Hide();
}
}
When the form is closing because of various reasons such as closing in code, the parent form is closing, Windows is shutting down, etc. then the closing will not be cancelled. Only when the window is being closed because the user closed the child form directly will you hide it.
To show a MDI child inside of a MDI parent, you can do the following:
MyParentForm parentForm = new MyParentForm();
parentForm.IsMdiContainer = true;
parentForm.Show();
MyChildForm childForm = new MyChildForm();
childForm.MdiParent = parentForm;
childForm.Show();