FrameworkElement (FE) derives from UIElement. FrameworkContentElement (FCE) derives from ContentElement. Since the framework is not built on a language that supports multiple inheritance (and thank god for that!), the divergence was necessary. There are parts of ContentElement that you wouldn't want in every FE and there are parts of UIElement that you wouldn't want in every FCE.
FCE basically exists to support the text formatting engine (which can be found in the MS.Internal.Text namespace). There are a few non-text classes that derive from FCE, but they do this just to be lightweight.
The goal was to make the programming experience for dealing with an FE and FCE as similar as possible. If anything, I think this makes the framework *more* elegant.
You can think of an FCE as having everything an FE has except support for layout/rendering. Of course, this is no small feature and you certainly would not want that kind of overhead in every text element. Imagine the perf if you tried to render every textual stroke using WPF’s layout engine... text is far too complex.
True, it’s weird to see the exact same properties, methods, interfaces, events, etc, defined on two completely different base classes. But I guess my general response is a big shrug. As long as Microsoft is willing to maintain the code, I don’t have a problem with it. (And in truth, much of the code shared between the classes is codegen’d anyway during the build process, so its really not that hard for them to maintain... clever chaps!)
Sidenote: IFE vs. LIFE: A mnemonic we used to use is “LIFE begins at UIElement”. That is to say, every UIElement supports Layout, Input, Focus, and Events. ContentElement gives you everything but the ‘L’. As such, the intersection of functionality between an FE and FCE is the IFE portion.
I recommend creating a helper class if you want to treat the IFE portion of framework objects in a polymorphic manner. It’s easy enough to implement... in fact, you can steal most of the implementation from the internal FrameworkObject class. :-)
Dr. WPF - Online Office at http://www.drwpf.com/blog/
Since the framework is not built on a language that supports multiple inheritance (and thank god for that!), the divergence was necessary.
It all begins with one parenthetical remark, doesn’t it? I guess I should just be happy that you are not complaining about my failure to capitalize the ‘g’ in god. ;-)
I totally respect your views on this, Bill. And I don’t think the MI concept is *bad*... I’m just not as convinced as you are that it’s really *good*. My reason for appreciating the current SI model is that it means we just don’t have to deal with various MI problems.
Note that I’m weighing in here with some hesitation because I have long since lost my true passion for the MI vs. SI debate. I currently fall in the SI camp as a result of first-hand experience with most of the known MI issues.
I will certainly give props to Eiffel for its approach to MI. I played with it back in 2004 and I liked the general approach for dealing with things like name clashes. At the same time, I found myself saying “here we go again” when the provided samples would use the redefine subclause without the select subclause, thereby breaking my polymorphic calls on base classes. This is by far, the biggest drawback with MI. It’s not that it doesn’t have the potential to be powerful and useful... it’s that it is so often poorly implemented. (Yes, you can make the same argument about SI, so I don’t base my opinion entirely on this.)
What it ultimately comes down to is this... I have yet to see a cost-benefit analysis of MI in which I was persuaded that the benefits outweigh the costs. I’m aware of the costs first-hand. What is the great benefit that will move me back to the MI camp? I’ve heard the theoretical benefits for the last 20 years, but every practical MI scenario I’ve experienced just reinforces my membership in the SI camp. (It always seems to involve working within some sort of flawed technology like COM.) [Uh-oh.... there's another parenthetical remark that is liable to devolve.]
All that said, I’m not going to rally against Microsoft if they someday decide to bring MI to C#. However, I’m pretty sure it will require some CLS changes. If I recall correctly, when I examined my Eiffel.net classes in reflector, they did not maintain the “is a” relationship for multiple base classes, but were instead flattened. (It’s been a while and maybe such things have been solved, but I’m guessing there are a few issues in the CLR that interfere with true MI support.)
If I had to place a bet, I’d guess that we will never see true MI in .NET just because of its current reputation (deserved or not). Microsoft probably doesn’t perceive the required investment as paying off for a feature that most shops will just avoid using. It would be an uphill battle, for sure, to bring MI back into wide acceptance. Yes, I’m fine with blaming that entirely on C++.