WPF Simplified Part 4: Logical and Visual trees

To be clear at the outset, there is only one object tree in WPF, which is created based on the nested relationships of the elements in the markup (the markup may be built via XAML or code). The logical and visual tree are two different ways of looking at this object tree. They are both subsets of the object tree.

When you’re creating some UI in XAML, for example,

<!-- Note: no x:Class, load this XAML using XmlReader.Create -->

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  Width="300" Height="300">
        <Button Height="100" Width="100" Content="Text" />

You may intuitively think of a tree structure that looks like the one below (arrows point to parent). In reality, the object tree is far more complex and has many more elements. This simplified subset of the object tree, which most closely matches the elements declared in the XAML, is called the logical tree.

                                                      Logical Tree

The elements in the object tree that derive from the Visual or Visual3D base class form the visual tree subset of the object tree. The visual tree consists of all the drawing primitives and other controls that are used to implement the UI. As you can see below, a lot more elements are included in the visual tree, even though you didn’t explicitly declare them (in the XAML above).

                                                              Visual Tree

The way to read the tree diagram above is: the TextBlock’s visual parent’s type is ContentPresenter, while it’s logical parent is null. Both of ContentPresenter’s visual and logical parent’s types are ButtonChrome. ButtonChrome’s visual parent’s type is Button, while it’s logical parent is null, and so on.

The Button’s visual tree comprises of a TextBlock, a ContentPresenter, a ButtonChorme, and the Button itself. Similarly, the Window’s visual tree comprises of a Border, an AdornerDecorator, a ContentPresenter, a Grid, and the Button along with it’s visual tree.

Setting visual properties on a visual parent propagates to visual descendants. For example, setting opacity, the IsEnabled property, or setting a transform on the parent applies to the children as well.

But why have two subsets of the full object tree? The purpose is that WPF uses the logical tree to iterate over child objects, propagate certain notifications, and also for resource lookup, and the visual tree to render visual objects, and for routed events.

WPF gives us a way to traverse both the logical and the visual trees using the LogicalTreeHelper and the VisualTreeHelper respectively. Using the these are simple enough,

// Traverse up the visual tree 
private void TraverseVisualTreeUp(DependencyObject element)
    while (element != null)
        element = VisualTreeHelper.GetParent(element);


// Traverse up the logical tree
private void TraverseLogicalTreeUp(DependencyObject element)
    while (element != null)
        element = LogicalTreeHelper.GetParent(element);

The FrameworkElement.Parent property also returns the logical parent. Elements in the object tree that derive from the ContentElement base class show up in the logical tree but not in the visual tree.

Another good article about logical/visual trees in WPF is here.


About soumya chattopadhyay
I live and work in Seattle, WA. I work with Microsoft technologies, and I'm especially interested in C#.

3 Responses to WPF Simplified Part 4: Logical and Visual trees

  1. Pingback: WPF Simplified Series « I.Net

  2. Pingback: WPF Simplified Part 6: Control Templates « I.Net

  3. Pingback: WPF Simplified Part 5: Control Templates « I.Net

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: