|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionThis article discusses nuances of and differences between the visual tree and logical tree in WPF. It also presents a small application with which you can investigate this topic further. If you are completely unfamiliar with the concepts of the visual tree and/or logical tree, I suggest you read this page in the SDK documentation first. BackgroundThe existing documentation about the visual tree and logical tree in the Windows SDK leaves much to be desired. Ever since I started with WPF, I have felt unsure about what exactly differentiates the two. I knew that the logical tree and visual tree both only contain visual elements and controls, right? Wrong. I knew that a It turns out that the element trees in WPF are rather complicated and require detailed knowledge of low-level WPF classes to work with them correctly. Walking an element tree in a generic fashion; where you assume no knowledge of its constituents; is not as simple as it might seem. Unfortunately WPF does not publicly expose a class which simplifies walking the element trees to the point where it is "really easy". At this point you might be wondering what makes walking the element trees so complicated. Good question. The answer has several parts, which are discussed in the following sections. The Visual TreeThe visual tree represents all of the elements in your UI which render to an output device (typically, the screen). The visual tree is used for many things like rendering, event routing, locating resources (if an element has no logical parent), and more. Walking up and down the visual tree can be a simple matter of just using VisualTreeHelper and some simple recursive methods. However, there is one wrinkle which makes this a little more complicated. Anything which descends from
Here is how the docs explain what it means that
So what does all this mean? Well, it means that you can't always just use DependencyObject FindVisualTreeRoot(DependencyObject initial)
{
DependencyObject current = initial;
DependencyObject result = initial;
while (current != null)
{
result = current;
if (current is Visual || current is Visual3D)
{
current = VisualTreeHelper.GetParent(current);
}
else
{
// If we're in Logical Land then we must walk
// up the logical tree until we find a
// Visual/Visual3D to get us back to Visual Land.
current = LogicalTreeHelper.GetParent(current);
}
}
return result;
}
This code walks up the logical tree when necessary, as seen in the The Logical TreeThe logical tree represents the essential structure of your UI. It closely matches the elements you declare in XAML, and excludes most visual elements created internally to help render the elements you declared. WPF uses the logical tree to determine several things including dependency property value inheritance, resource resolution, and more. Working with the logical tree is not nearly as clear-cut as the visual tree. For starters, the logical tree can contain objects of any type. This differs from the visual tree, which only contains instances of void WalkDownLogicalTree(object current)
{
DoSomethingWithObjectInLogicalTree(current);
// The logical tree can contain any type of object, not just
// instances of DependencyObject subclasses. LogicalTreeHelper
// only works with DependencyObject subclasses, so we must be
// sure that we do not pass it an object of the wrong type.
DependencyObject depObj = current as DependencyObject;
if (depObj != null)
foreach(object logicalChild in LogicalTreeHelper.GetChildren(depObj))
WalkDownLogicalTree(logicalChild);
}
A given This weirdness can all be boiled down to one word: templates. Controls and data objects have no intrinsic visual appearance; instead they rely on templates to explain how they should render. A template is like a cookie-cutter which can be "expanded" to create real live visual elements used to render something. The elements that are part of an expanded template, hereafter referred to as "template elements", form their own logical tree which is disconnected from the logical tree of the object for which they were created. Those little logical trees are what I refer to as "logical islands" in this article. You have to write extra code if you need to jump between logical islands/trees. Bridging those logical islands together, while walking up logical trees, involves making use of the DependencyObject GetTemplatedParent(DependencyObject depObj)
{
FrameworkElement fe = depObj as FrameworkElement;
FrameworkContentElement fce = depObj as FrameworkContentElement;
DependencyObject result;
if (fe != null)
result = fe.TemplatedParent;
else if (fce != null)
result = fce.TemplatedParent;
else
result = null;
return result;
}
Walking down the logical tree and jumping from one tree to the next is more difficult because there is no The Research ToolThis article is accompanied by a small console application which allows you to experiment with and investigate the element trees. It opens a WPF When you start the app, it looks like this:
After maximizing the console window and moving the WPF
Notice that the [YOU CLICKED HERE] text appears on the line in the console window which represents a Since If I were to hold Ctrl and left-click on the text itself, meaning on the
Notice how the logical tree is very different now. It is much smaller than before; the root is a If we were to hold Ctrl and right-click on the
Obviously the visual tree seen here is much larger than the original logical tree seen previously. It is interesting to note that the visual tree contains all of the visual elements involved with the ConclusionAt first glance, the element trees in WPF might seem to be fairly self-explanatory. Upon closer examination, though, it becomes apparent that they are not that simple. For most WPF programming tasks it is not important to be familiar with these details, but for some more advanced scenarios it becomes crucial information. Hopefully this article has helped shed some light on these arcane details. Revision History
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||