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