Archive

Posts Tagged ‘reference’

Reference to Self in XAML

April 9, 2009 3 comments

I’m always finding that I need to get a reference to the root element (this) in my XAML markup. If I’m in a situation that I can use a Binding, I can do something like this where I’m getting the Height of the current Window):

{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=Height}

However, there are many times that I need a reference to the root where I can’t use a binding. I really, really hope somebody will prove me wrong and show me there is a better way to do this that’s already built in to WPF, but since I haven’t been able to find anything, I added a MarkupExtension that uses reflection to get a reference to the private fields serviceProvider._Context._rootElement:

public class SelfExtension : MarkupExtension
{
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        object self = null;
        Type selfType = serviceProvider.GetType();
        FieldInfo contextFieldInfo = selfType.GetField("_context", BindingFlags.NonPublic | BindingFlags.Instance);
        if(contextFieldInfo != null)
        {
            object context = contextFieldInfo.GetValue(serviceProvider);
            Type contextType = context.GetType();
            FieldInfo rootElementFieldInfo = contextType.GetField("_rootElement", BindingFlags.NonPublic | BindingFlags.Instance);
            if(rootElementFieldInfo != null)
                self = rootElementFieldInfo.GetValue(context);
        }
        return self;
    }
}

Yes, this is a terrible hack using reflection to access private fields, and there’s a good chance it will go away in a future version of WPF…hopefully because Microsoft builds in their own extension to do this properly. If you know of a better way, please speak up!

[Update: Microsoft addressed this is .NET 4]

Here is a new version that doesn’t require reflection using the updated API in .NET 4:

public class SelfExtension : MarkupExtension
{
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return ((System.Xaml.IRootObjectProvider)serviceProvider).RootObject;
    }
}
Advertisements
Categories: WPF Tags: , , , ,