Trees in WPF
In many technologies, elements and components are organized in a tree structure where developers directly manipulate the tree to affect the rendering or behavior of an application. Windows Presentation Foundation (WPF) also uses several tree structure metaphors to define relationships between program elements.
This topic contains the following sections.
- Trees in WPF
- The Logical Tree
- The Visual Tree
- Trees, Content Elements, and Content Hosts
- Tree Traversal
- Routes for Routed Events as a "Tree"
- Resources and Trees
- Related Topics
Trees in WPF
The primary tree structure in WPF is the object tree. If you create an application page in XAML, then the tree structure is created based on the nesting relationships of the elements in the markup. If you create an application in code, then the tree structure is created based on how you assign property values for properties that implement the content model for a given object. In Windows Presentation Foundation (WPF), there are really two ways that the object tree is processed and conceptualized: as the logical tree and as the visual tree. The distinctions between logical tree and visual tree are not always necessarily important, but they can occasionally cause issues with certain WPF subsystems and affect choices you make in markup or code.
Even though you do not always manipulate either the logical tree or the visual tree directly, understanding the concepts of how the trees interact is a way to understand how property inheritance and event routing work in WPF.
The Logical Tree
In WPF, you add content to elements using properties. For example, you add items to a ListBox control using its Items property. By doing this, you are placing items into the ItemCollection of the ListBox control. To add objects to a DockPanel, you use its Children property. Here, you are adding objects to the UIElementCollection of the DockPanel. For a code example, see How to: Add an Element Dynamically.
In Extensible Application Markup Language (XAML), when you place list items in a ListBox or controls or other elements in a DockPanel, you also use the Items and Children properties, either explicitly or implicitly, as in the following example.
<DockPanel Name="ParentElement" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" > <!--implicit: <DockPanel.Children>--> <ListBox DockPanel.Dock="Top"> <!--implicit: <ListBox.Items>--> <ListBoxItem> <TextBlock>Dog</TextBlock> </ListBoxItem> <ListBoxItem> <TextBlock>Cat</TextBlock> </ListBoxItem> <ListBoxItem> <TextBlock>Fish</TextBlock> </ListBoxItem> <!--implicit: </ListBox.Items>--> </ListBox> <Button Height="20" Width="100" DockPanel.Dock="Top">Buy a Pet</Button> <!--implicit: </DockPanel.Children>--> </DockPanel>
Note that the property element tags are not explicitly needed because the XAML reader infers the property elements when it creates the objects that create the executable's runtime object representation of the application. For more information about how XAML syntax maps to the created logical tree, and inferred syntax elements, see XAML Syntax Terminology or XAML Overview.
The Purpose of the Logical Tree
The logical tree exists so that content models can readily iterate over their possible child objects, and so that content models can be extensible. Also, the logical tree provides a framework for certain notifications, such as when all objects in the logical tree are loaded.
In addition, resource references are resolved by looking upwards through the logical tree for Resources collections on the initial requesting object and then parent objects. The logical tree is used for resource lookup when both the logical tree and the visual tree are present. For more information on resources, see Resources Overview.
Overriding the Logical Tree
Advanced control authors can override the logical tree by overriding several APIs that define how a general object or content model adds or removes objects within the logical tree. For an example of how to override the logical tree, see How to: Override the Logical Tree.
Property Value Inheritance
Property value inheritance operates through a hybrid tree. The actual metadata that contains the Inherits property that enables property inheritance is the WPF framework-level FrameworkPropertyMetadata class. Therefore, both the parent that holds the original value and the child object that inherits that value must both be FrameworkElement or FrameworkContentElement, and they must both be part of some logical tree. However, the logical tree of parent versus child is permitted to be disjoint, with property value inheritance able to perpetuate through an intervening visually represented object that is not in a logical tree. In order for property value inheritance to work consistently across such a boundary, the inheriting property must be registered as an attached property. The exact tree used for property inheritance cannot be entirely anticipated by a helper class utility method, even at run time. For more information, see Property Value Inheritance.
The Visual Tree
In addition to the concept of the logical tree, there is also the concept of the visual tree in WPF. The visual tree describes the structure of visual objects, as represented by the Visual base class. When you write a template for a control, you are defining or redefining the visual tree that applies for that control. The visual tree is also of interest to developers who want lower-level control over drawing for performance and optimization reasons. One exposure of the visual tree as part of conventional WPF application programming is that event routes for a routed event mostly travel along the visual tree, not the logical tree. This subtlety of routed event behavior might not be immediately apparent unless you are a control author. Routing events through the visual tree enables controls that implement composition at the visual level to handle events or create event setters.
Trees, Content Elements, and Content Hosts
Content elements (classes that derive from ContentElement) are not part of the visual tree; they do not inherit from Visual and do not have a visual representation. In order to appear in a UI at all, a ContentElement must be hosted in a content host that is both a Visual and a logical tree participant. Usually such an object is a FrameworkElement. You can conceptualize that the content host is somewhat like a "browser" for the content and chooses how to display that content within the screen region that the host controls. When the content is hosted, the content can be made a participant in certain tree processes that are normally associated with the visual tree. Generally, the FrameworkElement host class includes implementation code that adds any hosted ContentElement to the event route through subnodes of the content logical tree, even though the hosted content is not part of the true visual tree. This is necessary so that a ContentElement can source a routed event that routes to any element other than itself.
The LogicalTreeHelper class provides the GetChildren, GetParent, and FindLogicalNode methods for logical tree traversal. In most cases, you should not have to traverse the logical tree of existing controls, because these controls almost always expose their logical child elements as a dedicated collection property that supports collection access such as Add, an indexer, and so on. Tree traversal is mainly a scenario that is used by control authors who choose not to derive from intended control patterns such as ItemsControl or Panel where collection properties are already defined, and who intend to provide their own collection property support.
The visual tree also supports a helper class for visual tree traversal, VisualTreeHelper. The visual tree is not exposed as conveniently through control-specific properties, so the VisualTreeHelper class is the recommended way to traverse the visual tree if that is necessary for your programming scenario. For more information, see Windows Presentation Foundation Graphics Rendering Overview.
Routes for Routed Events as a "Tree"
As mentioned before, the route of a routed event effectively travels along a tree that is a hybrid of the visual and logical tree representations, traveling either up or down the tree depending on whether it is a tunneling or bubbling routed event. The event route concept does not have a directly supporting helper class that could be used to "walk" the event route independently of raising an event that actually routes. There is a class that represents the route, EventRoute, but the methods of that class are generally for internal use only.
Resources and Trees
Resource lookup for immediate resources traverses basically the logical tree. (Immediate resources are resources defined on the page, as opposed to application resources or resources from themes.) Objects that are not in the logical tree can reference resources, but the resource lookup sequence begins at the point where that object is connected to the logical tree. Only logical tree nodes can have a Resources property that contains a ResourceDictionary, therefore there is no benefit in traversing the visual tree looking for resources.
However, resource lookup can also extend beyond the immediate logical tree. For application markup, the resource lookup can then continue onward to application resources and to theme support and system values. Themes themselves can also reference system values outside of the theme logical tree if the resource references are dynamic. For more information on resources and the lookup logic, see Resources Overview.