Monday, October 27, 2008

Silverlight and the Logical Tree

Those of you familiar with WPF may experience some disorientation when acclimating to Silverlight.  Although Silverlight has certain new and exciting capabilities currently lacking from WPF there are certain features missing  from Silverlight which you have come to know and love.  One of those features is the logical tree.  The official word from Microsoft is that the logical tree is not necessary in Silverlight because it does not support ElementName bindings.  That said there is a trick you can use if you would like to figure out if an element is the logical ancestor or descendent of another element: confirm that the other object is in the same name scope.  You can always find out if two elements are in the same name scope by calling the FindName method on one and passing in the name of the other object.

element.FindName(otherElement.Name) == otherElement

But what if an object does not have a name?  Well the answer is simple: you give it one.  It is relatively easy to ensure that each object has a unique name by creating a GUID.  Although it is unpleasant to assign names to elements in the visualtree for no other purpose than to determine if they are logically related to other elements it is currently the only way of discerning the information that I'm aware of.  Of course better ideas are always welcome. :-)

Using this trick we can write a logical tree helper class like the one available in WPF.  However instead of using the same API as WPF let's change it a little to make it more Linq friendly.  First we'll write  a GetVisualChildren function that returns the visual children as a sequence.


/// <summary> /// Retrieves all the visual children of a framework element. /// </summary> /// <param name="parent">The parent framework element.</param> /// <returns>The visual children of the framework element.</returns> internal static IEnumerable<DependencyObject> GetVisualChildren(this DependencyObject parent) { Debug.Assert(parent != null, "The parent cannot be null."); int childCount = VisualTreeHelper.GetChildrenCount(parent); for (int counter = 0; counter < childCount; counter++) { yield return VisualTreeHelper.GetChild(parent, counter); } }

That was easy.  Now we can run Linq queries on the visual children of an element.  Now let's write a function that recurses down the tree depth-first and grab every immediate descendent that is in the same name scope of the element.  In the interest of speed we'll manage the stack ourselves.

public static class LogicalTreeHelper { /// <summary> /// Retrieves all the logical children of a framework element using a /// depth-first search. A visual element is assumed to be a logical /// child of another visual element if they are in the same namescope. /// For performance reasons this method manually manages the stack /// instead of using recursion. /// </summary> /// <param name="parent">The parent framework element.</param> /// <returns>The logical children of the framework element.</returns> internal static IEnumerable<FrameworkElement> GetLogicalChildren(this FrameworkElement parent) { Debug.Assert(parent != null, "The parent cannot be null."); EnsureName(parent); string parentName = parent.Name; Stack<FrameworkElement> stack = new Stack<FrameworkElement>(parent.GetVisualChildren().OfType<FrameworkElement>()); while (stack.Count > 0) { FrameworkElement element = stack.Pop(); if (element.FindName(parentName) == parent) { yield return element; } else { foreach (FrameworkElement visualChild in element.GetVisualChildren().OfType<FrameworkElement>()) { stack.Push(visualChild); } } } } }

The EnsureName function just checks to see whether an element has a name and names it if it does not. There you have it: a LogicalTreeHelper for Silverlight. 


Rob said...

Could you guys please, please, just add a real logical tree? And don't forget Freezables too :)

Mark said...

Could you provide a small sample app in Silverlight?

Anonymous said...

Good stuff. One minor thing though; the way the stack is populated causes the logical childs to be returned in reversed order.

Affordable Luxurious Wedding Dress Blog said...

cheap wedding gowns,
discount bridal gowns,
China wedding dresses,
discount designer wedding dresses,
China wedding online store,
plus size wedding dresses,
cheap informal wedding dresses,
junior bridesmaid dresses,
cheap bridesmaid dresses,
maternity bridesmaid dresses,
discount flower girl gowns,
cheap prom dresses,
party dresses,
evening dresses,
mother of the bride dresses,
special occasion dresses,
cheap quinceanera dresses,
hot red wedding dresses

products said...

China Wholesale has been described as the world’s factory. This phenomenom is typified by the rise ofbusiness. Incredible range of products available with China Wholesalers “Low Price and High Quality” not only reaches directly to their target clients worldwide but also ensures that wholesale from china from China means margins you cannot find elsewhere and buy products wholesaleChina Wholesale will skyroket your profits.

products said...

Women’s nike tn Shox Rivalry est le modèle féminin le plus tendance de baskets pour le sport. tn chaussuresConcernant la semelle :Cheap Brand Jeans ShopMen Jeans - True Religion Jeans nike shoes & Puma Shoes Online- tn nike, le caoutchouc extérieur, l’EVA intermédiaire et le textile intérieur s’associent pour attribuer à la.ed hardy shirts pretty fitCharlestoncheap columbia jackets. turned a pair of double plays to do the trick.Lacoste Polo Shirts, , Burberry Polo Shirts.wholesale Lacoste polo shirts and cheap polo shirtswith great price.Thank you so much!!cheap polo shirts men'ssweate,gillette mach3 razor bladesfor men.As for

Anonymous said...


About Me

My photo
I'm a software developer who started programming at age 16 and never saw any reason to stop. I'm working on the Presentation Platform Controls team at Microsoft. My primary interests are functional programming, and Rich Internet Applications.