WPF - 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 trees are two different ways of looking at this object tree. They are both subsets of the object tree.

When we’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"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Width="300" Height="300">
  <Grid>
        <Button Height="100" Width="100" Content="Text" />
    </Grid>
</Window>

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.
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).
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)
    {
        Console.WriteLine(element.GetType());
        element = VisualTreeHelper.GetParent(element);
    }
}
AND
// Traverse up the logical tree
private void TraverseLogicalTreeUp(DependencyObject element)
{
    while (element != null)
    {
        Console.WriteLine(element.GetType());
        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.

Comments

  1. As I am fresher I have an interest in new Technology. So, now I am planning to learn Informatica in your blog i had some interesting concepts, it was crystal clear to read keep sharing thanks SAS Training in Chennai| SAS Course in Chennai

    ReplyDelete

Post a Comment

Popular posts from this blog

Facade Design Pattern

Auto Scroll in Common Controls

Convert typed library (.tlb) to .net assembly?