Mitch is tightly coupled to extender providers

Mitch has been thinking about extender providers vs. sub-classing of GUI tool-kits as a result of some internal mailing-list discussions. Here are my thoughts.

Firstly the reasons discussed for using sub-classing were 3-fold:

  1. A place to make “global” changed to the behavior of an item (change style to “flat”, fix memory leak or rendering problem)
  2. Create an “adapter” to reduce the surface area of complex controls, make API more familiar etc
  3. Remove coupling between application and underlying tool-kit (allowing you to potentially [1] swap something else in if the first one doesn’t cut it)

Extender providers are a way of applying a “cross-cutting concern” or “aspect” to a series of otherwise un-related or loosely related controls. This seems to be a special case of point #1 - you want to make global changes to the behavior of an item (say you want to add a tool-tip property and allow the control to display a tool-tip which it could not previously do before) but you don’t want to just do it to that control, you want to do it to lots of different types of controls. Extender providers do achieve this, and although the implementation has often struck me as a little crufty it does work. However extender providers fail to allow you to make global changes to the behavior of items in the tool-kit, and only let you “adapt“ an API one way - by extending it.

Lets say some of our developers have been naughty and are using colour-based cues on their buttons when they shouldn’t, and for consistency and accessibility reasons we always want our buttons to display in the normal windows colours. To do this using inheritance you would override the backcolor property, ignoring whatever was supplied in the setter, and in the constructor set the backcolor to the windows default. Maybe I just don’t have the extender-provider mind-set but I fail to see how extender providers would help you here. Sub-classing falls down in some areas because of sealed classes, non-virtual properties etc, but in many cases you can work around this too. For example lets assume backcolor was not virtual in our widget set’s button implementation - if we can inherit from the container that holds the widget (like…the form) and subscribe to some event (like load, re-draw etc) we can add code in our base form class (the form class is part of the widget set - we would have a base form class) to iterate through all the controls and set the button color appropriately. Not the most elegant solution (since we’re now adding non-obvious magical “hey why did all my buttons just change colour” behavior to our base form class) but sometimes it is appropriate. In the area of cross-cutting concerns there are approaches in .NET other than extender providers (such as attributes + interception, or attributes + reflection in some kind of container class or pipeline). Don’t get me wrong - I think the idea of extender providers doesn’t suck and while the implementation is not that great it does work. I believe they have their place, but I believe normal OO techniques should be more heavily favoured.

As to the fact that the designer and inherited controls don’t go well together - my first reaction was not to assume that inheritance was broken. Having said that I’m not a very “graphical“ programmer. When I look at an orchestration in biztalk I think of how much less screen realestate the same thing would take up in C#. When I look at the mapper I’m trying to visualize what sort of XSLT its going to generate. Maybe it’s just me.

[1] Notice I said potentially - like making all your database access calls through a single tier can potentially allow you to swap out oracle for SQL Server on the back end. It rarely happens in real life and (I’m told) the results are not pretty.