Does a form automatically call Dispose() for each control it contains when the form itself is dispos

R

Roberto Rocco

Hello,

Are all the controls of a form automatically disposed when the Dispose()
method of the form is called, or do I need to dispose them separately?

Or maybe better said: Is the Dispose() method of each control of the form
automatically called when the Dispose() method of the form is called?

On some postings here I could find that there is (was?) a bug where the
forms are (were?) missing to call Dispose() for their hosted controls.

In my concrete example: Do I have to call the Dispose() method for a
PictureBox myself or ist it done automatically when the Dispose() method of
the form is called?
(Of course, I understand that unmanaged resources that are not controls have
to be disposed by myself!)

Many thanks in advance,

Roberto Rocco.
 
A

Alex Feinman [MVP]

Roberto,

I did some research and it appears that form does not dispose of the child
controls automatically. I'm still researching it, and will post more
information as I have it. In th meantime I suggest that you explicitly call
Dispose on any control that needs to be disposed of in the Form.Dispose
override and then call Dispose on the form itself.

Also, if you have a picturebox with an image assigned to it, you will need
to call Dispose() on the image in the Form's Dispose() - otherwise the image
will stay in memory until it is garbage-collected and that may take a while
 
M

Myron Marston

In the project I've been working on, I had issues with Form dispose as
well. You can use Lutz Roeder's .NET Reflector
(http://www.aisto.com/roeder/dotnet/) to look into the internals of the
framework classes. Here are some things worth noting:

1. Form does not override dispose, so the behavior of dispose is that
of System.Windows.Forms.Contol (i.e. IDisposable Dispose() simply calls
Dispose(true); Dispose(true) simply releases the control's handle).
Note that Dispose will not be called on the controls contained on the
form.

2. Form.Dispose() is not automatically called when the form closes.
Form.Close() makes the necessary calls to dispose of the window handle
but skips calling Dispose directly.

3. Component contains the usual overridable Dispose(boolean) method,
but it does not implement IDisposable (How bizarre is that??)

In the project I've been working on, I've used the following pattern to
overcome these shortcomings, and it has worked quite well:

1. I have created a FormHelper component that is on all my forms. It
does a number of common tasks, including helping out with the dispose
issues. It handles the closing event of the form:

private void mForm_Closing(object sender, CancelEventArgs e)
{
if (e.Cancel) return;

// for some reason, dispose is not called on Form close, so call it
manually
Form.Dispose();
}

2. On my forms, I override Dispose(boolean) with the following code to
redirect dispose to FormHelper.DoFormDispose(). I could have called
this directly from the closing event handler, but this way I still have
a place to put additional form-specific disposing code, if need be.

Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
FormHelper.DoFormDispose()
End If
MyBase.Dispose(disposing)
End Sub

3. FormHelper.DoFormDispose() recursively disposes of all child
controls and also disposes of any components that implement the
IDisposable interface:

public virtual void DoFormDispose()
{
foreach (Control ctl in Form.Controls)
DoControlDispose(ctl);

// also dispose any IDisposable Components
ArrayList comps = GetDisposableComponents();
foreach (IDisposable d in comps)
{
// don't dispose controls, as they have already been disposed above
if (!(d is Control))
d.Dispose();
}
}

protected internal virtual void DoControlDispose(Control c)
{
foreach (Control ctl in c.Controls)
DoControlDispose(ctl);

c.Dispose();
}

protected virtual ArrayList GetDisposableComponents()
{
ArrayList list = new ArrayList();

foreach(FieldInfo fi in Form.GetType().GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance))
{
foreach(Type iFace in fi.FieldType.GetInterfaces())
{
if (iFace.Equals(typeof(IDisposable)))
list.Add(fi.GetValue(Form));
}
}

return list;
}

4. In order to make sure my custom components are disposed, they all
derive from this MyComponent class rather than the usual one:

#if NETCFDESIGNTIME
[
ToolboxItemFilter("System.CF.Windows.Forms",
ToolboxItemFilterType.Custom),
ToolboxItemFilter("NETCF", ToolboxItemFilterType.Require)
]
#endif
public class MyComponent : Component, IDisposable
{
// for some reason, Component does not implement IDisposable
// on the NETCF. To account for this, all my
// components derive from this so that they implement it

#region IDisposable Members

#if NETCFDESIGNTIME
public new void Dispose()
#else
public void Dispose()
#endif
{
this.Dispose(true);
}

#endregion
}

Let me know if you have any questions about this.
 
A

Alex Feinman [MVP]

I've been looking into it since yesterday and came pretty much to the same
conclusions. The FormHelper class seems to be handy. Thanks

--
Alex Feinman
---
Visit http://www.opennetcf.org
Myron Marston said:
In the project I've been working on, I had issues with Form dispose as
well. You can use Lutz Roeder's .NET Reflector
(http://www.aisto.com/roeder/dotnet/) to look into the internals of the
framework classes. Here are some things worth noting:

1. Form does not override dispose, so the behavior of dispose is that
of System.Windows.Forms.Contol (i.e. IDisposable Dispose() simply calls
Dispose(true); Dispose(true) simply releases the control's handle).
Note that Dispose will not be called on the controls contained on the
form.

2. Form.Dispose() is not automatically called when the form closes.
Form.Close() makes the necessary calls to dispose of the window handle
but skips calling Dispose directly.

3. Component contains the usual overridable Dispose(boolean) method,
but it does not implement IDisposable (How bizarre is that??)

In the project I've been working on, I've used the following pattern to
overcome these shortcomings, and it has worked quite well:

1. I have created a FormHelper component that is on all my forms. It
does a number of common tasks, including helping out with the dispose
issues. It handles the closing event of the form:

private void mForm_Closing(object sender, CancelEventArgs e)
{
if (e.Cancel) return;

// for some reason, dispose is not called on Form close, so call it
manually
Form.Dispose();
}

2. On my forms, I override Dispose(boolean) with the following code to
redirect dispose to FormHelper.DoFormDispose(). I could have called
this directly from the closing event handler, but this way I still have
a place to put additional form-specific disposing code, if need be.

Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
FormHelper.DoFormDispose()
End If
MyBase.Dispose(disposing)
End Sub

3. FormHelper.DoFormDispose() recursively disposes of all child
controls and also disposes of any components that implement the
IDisposable interface:

public virtual void DoFormDispose()
{
foreach (Control ctl in Form.Controls)
DoControlDispose(ctl);

// also dispose any IDisposable Components
ArrayList comps = GetDisposableComponents();
foreach (IDisposable d in comps)
{
// don't dispose controls, as they have already been disposed above
if (!(d is Control))
d.Dispose();
}
}

protected internal virtual void DoControlDispose(Control c)
{
foreach (Control ctl in c.Controls)
DoControlDispose(ctl);

c.Dispose();
}

protected virtual ArrayList GetDisposableComponents()
{
ArrayList list = new ArrayList();

foreach(FieldInfo fi in Form.GetType().GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance))
{
foreach(Type iFace in fi.FieldType.GetInterfaces())
{
if (iFace.Equals(typeof(IDisposable)))
list.Add(fi.GetValue(Form));
}
}

return list;
}

4. In order to make sure my custom components are disposed, they all
derive from this MyComponent class rather than the usual one:

#if NETCFDESIGNTIME
[
ToolboxItemFilter("System.CF.Windows.Forms",
ToolboxItemFilterType.Custom),
ToolboxItemFilter("NETCF", ToolboxItemFilterType.Require)
]
#endif
public class MyComponent : Component, IDisposable
{
// for some reason, Component does not implement IDisposable
// on the NETCF. To account for this, all my
// components derive from this so that they implement it

#region IDisposable Members

#if NETCFDESIGNTIME
public new void Dispose()
#else
public void Dispose()
#endif
{
this.Dispose(true);
}

#endregion
}

Let me know if you have any questions about this.
Roberto,

I did some research and it appears that form does not dispose of the
child
controls automatically. I'm still researching it, and will post more
information as I have it. In th meantime I suggest that you explicitly
call
Dispose on any control that needs to be disposed of in the Form.Dispose
override and then call Dispose on the form itself.

Also, if you have a picturebox with an image assigned to it, you will
need
to call Dispose() on the image in the Form's Dispose() - otherwise the
image
will stay in memory until it is garbage-collected and that may take a
while
 

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