Thursday, February 16, 2006 3:57 AM
This seems like such a basic need that I am mystified why the brilliant minds at Microsoft have not made it possible via the .NET languages, .NET framework, or whatever would make it possible.
Case in point:
Take a TreeView class which contains a private read only TreeNodeCollection class. The TreeNodeCollection class is responsible for Add(), Remove(), InsertAt(), etc. Well, it's very easy to inherit from the TreeView, but then if you want to override the Add() or other TreeNodeCollection class methods, you're screwed. It's impossible. You're only alternative is a sloppy greasy fat ugly hairy hack, like implementing your own Add(), Remove(), InsertAt() functions in the treeview itself and then just be careful to not go through the TreeView.Nodes collection to do those functions. That is a pretty disgusting ugly hack if you ask me. Not nearly as elegant as being able to override the TreeNodeCollection and for the TreeView to use your overridden version instead. This would not be a case of multiple inheritance because TreeNodeCollection does not inherit from TreeView, so I am really confused, dismayed, and sickened by the lack of ingeniuity shown by people who should be thousands of times as intelligent as I.
Thanks for any input, and sorry if this is in the wrong forum, but I don't know if it's a language issue or a framework issue or what. I just know I need this functionality and it SUCKS to not have it.
Thursday, February 16, 2006 2:54 PMModerator
You can derive a class from a nested class. However the purpose of a nested class is to isolate a type that is specific to a class from the rest of the system so I don't know why you would. However in your case this isn't the issue. TreeNodeCollection is a public class not a nested one.
The problem you are seeing is a design issue. TreeNodeCollection, as are all collections in the framework, is not really designed for extensibility. Even the newest collections (Collection<T>) only supports extensibility superficially. Unless a class is sealed or static you can always derive from it. You might not be able to overload anything but you can derive from it.
The problem with collections in general is that they are not extensible enough for some things. Imagine for a moment that you need to lock some resource while you are updating a collection's elements. You can't do this in the existing implementations. At least not correctly. That is because the class wasn't really designed for this level of extensibility. You can definitely react to an item being added but you can't react globally to a block of items being added. There are other limits as well. For the older controls (like TreeNodeCollection) extensibility doesn't exist at all. It is a design limitation.
Even if TreeNodeCollection was completely extensible it would still be a mute point. The problem is that TreeView is responsible for creating the collection. A derived TreeView class never gets a choice as to what collection class to instantiate. Therefore without a change in TreeView there is nothing you can do. Web controls actually take an approach that I like and use personally in extensible classes. Web controls require a style in order to display properly. The style is of type ControlStyle but it is not directly created by the web control base class. Instead the web control base class calls a virtual method to create the style. The default implementation creates a ControlStyle but derived classes can create whatever they want. This is useful because ControlStyle is great for a single element but when you are talking about tables or other complex objects then ControlStyle isn't sufficient. Therefore controls that render tables actually return a TableStyle (through the overloaded method). This technique gives the base web control a standard interface but gives derived classes more control over what they can do. In the case of TreeView it would be necessary for the class to call a virtual method (like CreateNodeCollection) that, by default, returns a TreeNodeCollection yet can be overridden in a derived class to create some custom TreeNodeCollection-derived object.
Again it all boils down to design. To be fair it is more difficult then you think to build a class for extensibility. Some people believe that everything should be extensible always but I disagree. Having everything be extensible would complicate the design of even simple classes. Furthermore performance would suffer. I follow the philosophy of restricting everything and then opening up the class as needed for extensibility. This makes creating a solid design easier. Besides you can always open a class more later on without breaking existing clients.
As an aside you should remember that the original framework was being written at the same time the TreeView class (and others) were being developed. Furthermore the design guidelines that are now available for .NET were still in development back then. Hindsight is 20/20. Many people from MS have admitted that the framework does not follow all the guidelines in the documentation or specified by FxCop. Some of these are fixed in subsequent releases but many would require breaking changes. Most developers would rather have a component that doesn't quite meet the design guidelines rather than having to modify their code to work with a guidelines-compliant version.
As a final note you might be able to accomplish what you want by hooking various events on the TreeView and TreeNode classes. I have had good luck doing that. It isn't as easy and not always possible but it works.
Michael Taylor - 2/16/06