Finding ancestor elements in WPF

Philipp Sumi recently posted a method that uses VisualTreeHelper.GetParent to find an ancestor of a WPF element. The problem with using VisualTreeHelper.GetParent is that it doesn’t work with “content elements” like Hyperlink, Run, etc., which means that his TryFindFromPoint method would fail if the mouse cursor was over one of those types of elements. We’ve had to write our own GetParent method that traverses through content elements:

    public static DependencyObject GetParent(DependencyObject obj)
    {
        if (obj == null)
            return null;
        ContentElement ce = obj as ContentElement;
        if (ce != null)
        {
            DependencyObject parent = ContentOperations.GetParent(ce);
            if (parent != null)
                return parent;
            FrameworkContentElement fce = ce as FrameworkContentElement;
            return fce != null ? fce.Parent : null;
        }
        return VisualTreeHelper.GetParent(obj);
    }

We only recently discovered ContentOperations.GetParent; I won’t be surprised if there are other “GetParent” methods hiding in WPF that we’ll eventually need to support as well.

We also have an ancestor-finding method that avoids recursion:

    public static T FindAncestorOrSelf<T>(DependencyObject obj)
        where T : DependencyObject
    {
        while (obj != null)
        {
            T objTest = obj as T;
            if (objTest != null)
                return objTest;
            obj = GetParent(obj);
        }
        return null;
    }

It’s been fun finding so much great WPF content in blogs; I hope the trend continues!

Update: If you want to eliminate the ‘parent’ and ‘fce’ temporary variables from GetParent, you can use our IfNotNull extension method and replace that block of code with:

    return ContentOperations.GetParent(ce) ??
        (ce as FrameworkContentElement).IfNotNull(fce => fce.Parent);

Posted by Ed Ball on February 06, 2008