System.Windows.Forms.ColumnHeader and IDisposable

Z

Zachary Turner

Hello,

I'm a bit new to .NET and WindowsForms, and I don't like it when I run
across something that I don't understand. So I'm hoping I can clear up
some info for myself here and maybe learn a little bit more in the
process. :)

So anyway, the ColumnHeader class implements IDisposable interface
indirectly through one of its base classes. When and where does
Dispose actually get called? I'm sure this applies to many aspects of
..NET and Windows Forms, but I ask about this because it's the specific
case the got me thinking about this. It's important to me because I
have a situation where I add and remove Column Headers from the list
view dynamically. In fact, I even allow the user to create new types
of columns, all at runtime. I thought maybe somewhere in the
Listview.Dispose source code it loops through its Columns collection
calling Dispose on everything, but then what about Columns that I
remove at runtime and aren't in in the ListView whenever
ListView.Dispose is called? And on that note, when IS ListView.Dispose
called anyway? Probably in another loop from UserControl.Dispose or
Form.Dispose, but when are those called? My code simply allocates a
new form, stores it in a member variable, and then forgets about it.
Likewise with all sample code I've seen in books and MSDN.

Is this something I shoudl be worrying about? Why does it need to
implement IDisposable anyway? What system resources are being held
under the hood for which a finalizer is insufficient?

Thanks, I hope my question is clear, it's a little hard to convey my
confusion.

Zach
 
K

Kalpesh

Zach,

As I understand, for dynamically adding/removing columnheaders, you
should call dispose manually, as they will go unaccounted - when the
listview gets disposed

Experts in winforms could help here.
 
J

Jay B. Harlow [MVP - Outlook]

Zachary,
Most of Windows Forms Controls are based on Win32 Windows, so they hold
Win32 windows handles. Its preferred that you release the Win32 window
handle when the form closes. Remember that Dispose is called
deterministically, while Finalize is called non-deterministically. If you
want for the GC to release the Win32 window handles you may be waiting a
"long time" which may cause undue pressure on Win32 GDI. Implementing &
calling IDisposable.Disposed is advisable whenever you have unmanaged
resources. The new Using statement in VB 2005 simplifies calling Dispose for
you...

To this end; the Form itself will call Dispose of all the controls it owns &
those controls will call Dispose of all the controls they own & so on.

Form.Dispose is called either implicitly or explicitly when the Form is
closed (Form.Close). If you use Form.ShowDialog() then you need to
explicitly call Form.Dispose, if you use Form.Show() then Form.Dispose is
implicitly called for you. If your form is part of a MDI app, it sounds like
you need to explicitly call Form.Dispose.

http://msdn2.microsoft.com/en-us/library/system.windows.forms.form.close.aspx

For example, to show a dialog box I use code similar to:

' VB 2005 syntax
Using dialog As New OptionsDialog()
If dialog.ShowDialog() = DialogResult.Ok Then
' save results of dialog
End If
End Using ' causes Form.Dispose to be called.

' VB 2002 & 2003 syntax
Dim dialog As New OptionsDialog
Try

If dialog.ShowDialog() = DialogResult.Ok Then
' save results of dialog
End If
Finally
' assuming that dialog is not nothing...
dialog.Dispose()
End Finally


In your case where you are removing ColumnHeader's from the collection &
"discarding them", I would recommend you call ColumnHeader.Dispose before
you "discard them".

When to call Dispose?

* Call Dispose when the type itself implements IDisposable

* Call Dispose when the type or one of its base classes *overrides*
Dispose(Boolean) if the class inherits from System.ComponentModel.Component
or System.ComponentModel.MarshalByValueComponent

* Do not explicitly call Dispose on classes deriving from
System.Windows.Forms.Control for instances placed on a
System.Windows.Forms.Form as Form will implicitly dispose of them when the
form is Disposed

* Call Dispose on System.Windows.Forms.Form objects when Form.ShowDialog is
used.

* Do not explicitly call Dispose on System.Windows.Forms.Form objects if
Form.Show is used as Dispose will be implicitly called when the form is
closed

* Do not explicitly call Dispose on classes deriving from
System.Web.UI.Control as it will be implicitly called as part of the normal
ASP.NET page processing

I consider the second rule controversial as it relies on using ILDASM or
Reflector to find out implementation details of a class. Its meant for
classes such as DataSet, that have an inherited Dispose, but Dispose doesn't
really do anything.

These rules are based on private discussions with other MVPs & discussions
held in the newsgroups earlier in 2005.

These rules apply to objects that you create, explicitly or implicitly.
Objects that you "own".

Disposable Objects that are passed to you as a parameter of a method (such
as the Graphics object on the Paint event) should not have their disposed
method call, as the system calls it as part of the method that raises the
event.

Objects that something else "owns" should normally be disposed of by the
"owning" object.


--
Hope this helps
Jay B. Harlow [MVP - Outlook]
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


| Hello,
|
| I'm a bit new to .NET and WindowsForms, and I don't like it when I run
| across something that I don't understand. So I'm hoping I can clear up
| some info for myself here and maybe learn a little bit more in the
| process. :)
|
| So anyway, the ColumnHeader class implements IDisposable interface
| indirectly through one of its base classes. When and where does
| Dispose actually get called? I'm sure this applies to many aspects of
| .NET and Windows Forms, but I ask about this because it's the specific
| case the got me thinking about this. It's important to me because I
| have a situation where I add and remove Column Headers from the list
| view dynamically. In fact, I even allow the user to create new types
| of columns, all at runtime. I thought maybe somewhere in the
| Listview.Dispose source code it loops through its Columns collection
| calling Dispose on everything, but then what about Columns that I
| remove at runtime and aren't in in the ListView whenever
| ListView.Dispose is called? And on that note, when IS ListView.Dispose
| called anyway? Probably in another loop from UserControl.Dispose or
| Form.Dispose, but when are those called? My code simply allocates a
| new form, stores it in a member variable, and then forgets about it.
| Likewise with all sample code I've seen in books and MSDN.
|
| Is this something I shoudl be worrying about? Why does it need to
| implement IDisposable anyway? What system resources are being held
| under the hood for which a finalizer is insufficient?
|
| Thanks, I hope my question is clear, it's a little hard to convey my
| confusion.
|
| Zach
|
 
Z

Zachary Turner

Hi Jay, I appreciate your detailed response, it's given me a bit to
think about. In trying to incorporate these ideas, I have a situation
where I have a UserControl derived class. This is done to facilitate
the implementation of the standard tree/panel pattern you see in many
applications. Tree Control on the left, panel on the right that
changes depending on which node in the tree you click. I implement the
panel on the right as a class which derives from UserControl. It's
this class that has the listview in question, with the dynamic
ColumnHeader objects.

I decided that the appropriate time to call Dispose for my
ColumnHeaders would be at such time that the user decides to remove the
node from the tree (by right clicking the node in the Tree and choosing
Delete from a menu that pops up). Since that UserControl object is no
longer accessible, may as well free the resources then. However, the
UserControl class does not allow me to override the Dispose() method,
because it was not declared as virtual in the base class. It seems
rather hackish to write my own method like

public void DisposeTwo()
{
//Dispose column headers
}

and then in the Tree Node deletion code do

Panel.DisposeTwo();
Panel.Dispose();

Is there a more elegant way to handle this? Why doesn't UserControl
allow me to override its Dispose() method?
 
K

Kalpesh

Zach,

"Dispose" method has 1 overload which is marked virtual.
Hence, you can override that methods inside your usercontrol

protected override void Dispose(bool disposing)
{
....
}

AFAIK, the container of the usercontrol will call Dispose method on
your usercontrol - which will invoke the UserControl's Dispose method.
This will in turn call Disposing(true)
And that will make it call overriden implementation inside your
usercontrol class

HTH
Kalpesh
 
Z

Zachary Turner

Haha, of course. I feel silly now. I guess due to the fact that .NET
2005 uses partial classes I didn't even notice that version of dispose,
since the designer puts that override in the fragment corresponding to
the designer's code. I just typed "protected override void " in my
class definition, and Dispose wasn't an option in the Intellisense so I
thought somethign was wrong.

It's clear now, thanks :)

By the way, I'm not sure that in my case the container of the
UserControl will invoke the UserControl's dispose method. The reason
is that, like I said, I'm adding and removing the appropriate
UserControl from the container's Controls collection at runtime. So
there's only one visible at any given time, but in reality there's any
number of them allocated in memory. Hence, it can only know to
Dispose() of the one thats in its Controls collection, and the rest are
up to me to Dispose of as I see fit. Is this right?
 
J

Jay B. Harlow [MVP - Outlook]

| Hence, it can only know to
| Dispose() of the one thats in its Controls collection, and the rest are
| up to me to Dispose of as I see fit. Is this right?
Correct.

I would call Dispose on the control that I removed it from the Controls
collection.

I don't see a real need to override Dispose, the standard one should be
doing what you want. Do you have disposable members on your control that are
not Controls or Components?

Controls & Components, should (should) register themselves with the owning
control; the owning control should then call their Dispose method...


--
Hope this helps
Jay B. Harlow [MVP - Outlook]
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


| Haha, of course. I feel silly now. I guess due to the fact that .NET
| 2005 uses partial classes I didn't even notice that version of dispose,
| since the designer puts that override in the fragment corresponding to
| the designer's code. I just typed "protected override void " in my
| class definition, and Dispose wasn't an option in the Intellisense so I
| thought somethign was wrong.
|
| It's clear now, thanks :)
|
| By the way, I'm not sure that in my case the container of the
| UserControl will invoke the UserControl's dispose method. The reason
| is that, like I said, I'm adding and removing the appropriate
| UserControl from the container's Controls collection at runtime. So
| there's only one visible at any given time, but in reality there's any
| number of them allocated in memory. Hence, it can only know to
| Dispose() of the one thats in its Controls collection, and the rest are
| up to me to Dispose of as I see fit. Is this right?
|
 
Z

Zachary Turner

But I may want to add it back to the collection later. I guess it
comes down to when are the Windows resources allocated? Are they
allocated when the object is constructed, or are they allocated in
Controls.Add? I have been assuming that they are allocated in the
constructor, and since I may add the same control back to the form
after I manually remove it, I wasn't calling Dispose at the time I
removed it, but rather when the user performed an operation that made
that object completely invalid from that point forth.
 
K

Kalpesh

Hi Zach,

AFAIK, you will have to dispose off controls that you add/remove during
the lifetime of the container.

Any other controls (which are added to the container), which will
remain till the end of the container dispose. These controls will be
disposed off by the container, when it gets disposed. Just like Jay has
commented

<snip>
Controls & Components, should (should) register themselves with the
owning
control; the owning control should then call their Dispose method...
</snip>

Experts: please correct me, if I am wrong in my understanding.

Kalpesh
 
Z

Zachary Turner

Sorry, I'm still confused :( lol.

My understanding is that Jay was saying I should Dispose my controls
immediately after calling Controls.Remove(); e.g. my code should look
like this.

Control c = GetControlSomehow();
Controls.Remove(c);
c.Dispose();
//Do more work


However, just because I removed it from the Controls collection doesn't
mean I'm finished with it. At some point in time later, I want to add
it back to the collection. E.g.

Control c = GetControlSomehow();
Controls.Remove(c);
//Do more work, I don't want to call Dispose() yet because I'm not
actually done with c.
Controls.Add(c);
//Do even more work.
Controls.Remove(c);
//Finally I'm really done with c
c.Dispose();

I understand that I need to call Dispose() manually on any control that
is NOT in the collection when the container's Dispose() method is
called, but does the above snippet have a resource leak?
 
K

Kalpesh

Zach,

AFAIK, for any control that you are adding & removing dynamically
(which will not remain till the end of the container), should be
disposed off.

All other controls - which remain till the end of the form's dispose
will be taken care by the form when it gets disposed.

HTH
Kalpesh
 
Z

Zachary Turner

Forgive me if I'm still being dense :( I know it needs to be disposed
of. My question is -when- to dispose of it. When I remove it for the
first time, or when I remove it for the last time?
 
J

Jay B. Harlow [MVP - Outlook]

Zachary,
| When I remove it for the
| first time, or when I remove it for the last time?
When you remove it for the last time of course ;-)

If you are putting the same column back into the collection, then you need
to dispose of it when you remove it for the last time. As it won't be
usuable per se if you try to use it after its been disposed (any underlying
Win32 handles would have been closed).

If you are creating a new column each time you put a column in the
collection then you need to dispose of it when you remove it for the first
time, which also happens to be the last time for that specific column, as
you are creating a new column when you add it back...

--
Hope this helps
Jay B. Harlow [MVP - Outlook]
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


| Forgive me if I'm still being dense :( I know it needs to be disposed
| of. My question is -when- to dispose of it. When I remove it for the
| first time, or when I remove it for the last time?
|
 
Z

Zachary Turner

Thanks, that clears everything up :) I just wasn't sure if the actual
creation of handles and GDI resources occured in the constructor of the
class, or in the Controls / Columns.Add() function.
 

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