|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
System.Windows.Forms.ColumnHeader and IDisposableI'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 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. 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. -- Show quoteHope this helps Jay B. Harlow [MVP - Outlook] ..NET Application Architect, Enthusiast, & Evangelist T.S. Bradley - http://www.tsbradley.net "Zachary Turner" <divisorthe***@gmail.com> wrote in message news:1147842880.306346.153310@i39g2000cwa.googlegroups.com... | 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 | 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? 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 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? | Hence, it can only know to I would call Dispose on the control that I removed it from the Controls | 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. 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... -- Show quoteHope this helps Jay B. Harlow [MVP - Outlook] ..NET Application Architect, Enthusiast, & Evangelist T.S. Bradley - http://www.tsbradley.net "Zachary Turner" <divisorthe***@gmail.com> wrote in message news:1147987873.179318.72220@j33g2000cwa.googlegroups.com... | 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? | 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. 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 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? 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 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? Zachary,
| When I remove it for the When you remove it for the last time of course ;-)| first time, or when I remove it for the last time? 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... -- Show quoteHope this helps Jay B. Harlow [MVP - Outlook] ..NET Application Architect, Enthusiast, & Evangelist T.S. Bradley - http://www.tsbradley.net "Zachary Turner" <divisorthe***@gmail.com> wrote in message news:1148317301.028820.246910@g10g2000cwb.googlegroups.com... | 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? | |
|||||||||||||||||||||||