Exploring the WPF Logical and Visual Trees

February 10th, 2006

As you begin to develop WPF applications it becomes helpful to understand the concepts of the logical tree and visual tree. When building an application in WPF using XAML or C#, you nest layout elements (such as Grid, StackPanel, DockPanel), controls (TextBlock, TextBox, ListBox, CheckBox, ScrollBar, etc…) and control content to create your windows, custom controls, whatever. Each element that you explicitly add to your window, be it layout, control or content will become part of the window’s logical tree. This tree is the exact representation of what you have specified to be displayed. On the other hand, there is also a corresponding visual tree which contains a number of additional UI element classes for each entry in the logical tree. Examining the visual tree really lets you see the building blocks that the WPF framework uses to display your controls.

Let’s dive into a little demonstration. I’ve written the following C# class, exposing utility methods to recursively print a logical tree or visual tree, given a root UI element.

     public class VisualUtilities
     {

        private int indentDepth = 0;

        public void PrintVisualTree(Visual v)
        {
            string name = null;

            increaseIndent();

            if (v is FrameworkElement)
                name = ((FrameworkElement) v).Name;

            print("Visual Type: " + v.GetType().ToString() + (name != null ? ", Name: " + name : ""));

            // recurse through the children
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(v); i++)
            {
                PrintVisualTree(VisualTreeHelper.GetChild(v, i));
            }
            decreaseIndent();
        }

        public void PrintLogicalTree(Object obj)
        {
            increaseIndent();

            if (obj is FrameworkElement)
            {
                FrameworkElement fe = (FrameworkElement)obj;
                print("Logical Type: " + fe.GetType() + ", Name: " + fe.Name);

                // recurse through the children
                IEnumerable children = LogicalTreeHelper.GetChildren(fe);
                foreach (object child in children)
                {
                    PrintLogicalTree(child);
                }

            }
            else
            {
                // stop recursing as we certainly can't have any more FrameworkElement children
                print("Logical Type: " + obj.GetType());
            }

            decreaseIndent();

        }

        private void print(String line)
        {
            string indent;
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < indentDepth; i++)
                builder.Append("\t");

            builder.Append(line);
            Console.WriteLine(builder);
        }

        private void increaseIndent()
        {
            indentDepth++;
        }

        private void decreaseIndent()
        {
            indentDepth--;
        }
    }

A few notes about this code:

  • The PrintLogicalTree() method takes in a parameter of Object. This is because elements in the logical tree may extend from FrameworkElement (in the case of a control or layout) or be any other type of object (in the case of control content which could be anything from a string to an image). The base case of the recursion is that we've hit something which isn't a FrameworkElement, so we definitely won't have any logical children to continue recursing through.
  • The "Name" property is defined at the FrameworkElement level, not the more abstract Visual level. Therefore to make the output of the visual tree nicer and print the given name of any logical elements that we pass, we must cast to FrameworkElement.
  • Note the difference in API between the LogicalTreeHelper and VisualTreeHelper. LogicalTreeHelper supports the GetChildren(FrameworkElement parent) method to give you an IEnumerable. In constrast VisualTreeHelper makes you use GetChildrenCount(Visual parent) and then iterate through that count using GetChild(Visual parent, int childIndex). Why the API difference for something which is essentially the same thing? My answer from Microsoft,"It was probably coded by two different developers."

Now let's create a simple XAML window which contains just a single button:

The XAML layout:

<Window x:Class="Test.Window1"
    xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
    Title="Test"
    >

    <Grid x:Name="myGrid">
      <Button x:Name="button1" Click="Button1Clicked">Some Content</Button>
    </Grid>
</Window>

And the C# code behind:

public partial class Window1 : Window
{
        public Window1()
        {
            InitializeComponent();
        }

       private void Button1Clicked(object sender, RoutedEventArgs e)
       {

            VisualUtilities util = new VisualUtilities();
            Console.WriteLine("Logical Tree:");
            util.PrintLogicalTree(this);
            Console.WriteLine("Visual Tree:");
            util.PrintVisualTree(this);

        }

    }

I've wired the Click event of the button to an event handler which will invoke our utility methods. Here is the corresponding output (I've bolded the logical elements at there positions in the visual tree so that you can see it more easily):

     Logical Tree:
     Logical Type: Test.Window1, Name:
              Logical Type: System.Windows.Controls.Grid, Name: myGrid
                     Logical Type: System.Windows.Controls.Button, Name: button1
                           Logical Type: System.String

     Visual Tree:
     Visual Type: Test.Window1, Name:
              Visual Type: System.Windows.Controls.Border, Name:
                     Visual Type: System.Windows.Controls.Grid, Name:
                           Visual Type: System.Windows.Documents.AdornerDecorator, Name:
                                  Visual Type: System.Windows.Controls.ContentPresenter, Name:
                                         Visual Type: System.Windows.Controls.Grid, Name: myGrid
                                                Visual Type: System.Windows.Controls.Button, Name: button1
                                                       Visual Type: Microsoft.Windows.Themes.ButtonChrome, Name: Chrome
                                                              Visual Type: System.Windows.Controls.ContentPresenter, Name:
                                                                     Visual Type: System.Windows.Controls.TextBlock, Name:
                                  Visual Type: System.Windows.Documents.AdornerLayer, Name:
                           Visual Type: System.Windows.Controls.Primitives.ResizeGrip, Name: WindowResizeGrip

You can see that in the space between the Window element and the Grid element that we defined in the logical tree, the WPF framework actually inserts another 4 UI elements to build the display, a Border, a Grid, an AdornerDecorator and a ContentPresenter. Also note that the string which contained the button content got turned into a ContentPresenter visual object containing a TextBlock (a button extends from ContentControl which allows you to place any kind of WPF content within the button. At display time, the WPF framework sees that my logical content was a string, so it added a TextBlock to the ContentPresenter object).

You will not have to worry about any of this when you first start developing WPF apps. However when it comes to troubleshooting issues or trying to do more advanced things like scaling, resizing or replacing portions of your window content, it helps to understand the tree structure actually representing your window.

4 Responses to “Exploring the WPF Logical and Visual Trees”

  1. Damien Morton Says:

    This seem to be broken in the Feb CTP.

  2. CosminB [BRT] Says:

    In reply to:
    [ Note the difference in API between the LogicalTreeHelper and VisualTreeHelper. LogicalTreeHelper supports the GetChildren(FrameworkElement parent) method to give you an IEnumerable. In constrast VisualTreeHelper makes you use GetChildrenCount(Visual parent) and then iterate through that count using GetChild(Visual parent, int childIndex). Why the API difference for something which is essentially the same thing? My answer from Microsoft,”It was probably coded by two different developers.” ]

    I think that a better reason would be because of the difference between the two trees. In the visual tree, the order of the elements is important, unlike the logical tree. Thus you cannot use IEnumerable here, because the interface states it cannot guarantee the order of the elements in a foreach statement. Let me know if I’m wrong.

    Cheers,
    Cosmin.

  3. Bookmark Base blog Says:

    Little usability tip…

    *screaming*
    People! Do not ever-ever-ever change look and behaviour of common controls. This confuses user too much.
    If you use tree control – it has to have [+] and [-] buttons. If you use list – it should be sortable by clicking on column headers. I…

  4. msdn Austria : Exploring the WPF Logical & Visual Trees Says:

    [...] In WPF werden Controls in zwei Bäumen gespeichert- dem Logical Tree und dem Visual Tree. In diesem Beispiel sehen Sie, wie Sie die beiden Control-Trees “durchforsten” und die Unterschiede zwischen beiden herausfinden können! [...]