If you are familiar with WPF you are aware that the the grand daddy of all controls is FrameworkElement. It is defined in the PresentationFramework.dll assembly and derives from UIElement (defined in PresentationCore.dll). Its purpose is to serve as a base element for all framework related stuff: styles, inheritance context, etc. However there is another framework element - FrameworkContentElement. The main distinct between them is that the later did not defines its own rendering behavior (its inheritors should do so). This is way properties like: (Actual)Width or (Actual)Height are not present at FrameworkContentElement. If you examine the classes that derive from FrameworkContentElement you will find out that they are mainly text and document related ones.

 image

So, what's the deal?

Looking through the MSDN documentation you will find out that: "FrameworkContentElement deliberately parallels many of the same APIs as FrameworkElement." However they did not implement a common interface. For example if you want to access the DataContext property (present at both classes) you should check explicitly for each type like this:

var dataContect = "DataContext";

var frameworkElement = sender as FrameworkElement;

if ( frameworkElement != null )

{

    frameworkElement.DataContext = dataContect;

}

else

{

    var frameworkContentElement = sender as FrameworkContentElement;

    if ( frameworkContentElement != null )

    {

        frameworkContentElement.DataContext = dataContect;

    }

}

This is not good and pretty as it should be. Let's fix it. Introducing the IFrameworkElement - the missing interface.

IFrameworkElement

IFrameworkElement interface contains all matching members from FrameworkElement and FrameworkContentElement. It also implements IFrameworkInputElement and ISupportInitialize, which both classes implement as well. The way to work with it is to call an extension method (AsFrameworkElement()) defined for a DependencyObject that will return the type as IFrameworkElement if the target is FrameworkElement or FrameworkContentElement, otherwise it will return null.  Here is now you can operate with it:

// sender is DependencyObject

var dataContext = "DataContext";

IFrameworkElement frameworkElement = sender.AsFrameworkElement();

if (frameworkElement != null)

{

    frameworkElement.DataContext = dataContect;

}

Why DependencyObject as target?

If you wonder why the method is defined on DependencyObject - simply because this is the common ancestor of both classes.

How is it implemented?

Internally there are two wrappers that wrap FrameworkElement and FrameworkContentElement and implement IFrameworkElement. All the calls to the interface are send to the wrapped element. The actual code is very simple, but about 624 lines long for each element. (It will be a much simpler one line implementation in a dynamic language - C# 4.0 is coming :) ).

You can find a sample solution here. The code can be found on CodePlex too.

Have fun.


Related Posts

Comments

Comments are disabled in preview mode.