Silverlight
Silverlight Object Trees

You can reference objects in the Silverlight object tree in Silverlight during run-time, either in managed code or JavaScript. This topic describes how to work with the object tree in the Silverlight managed API.

This topic contains the following sections.

Prerequisites

This topic assumes you have read XAML Overview and Silverlight Architecture.

Object Trees

An object tree is a conceptualization of how objects that are created and exist in the Silverlight content at run-time are related to each other. The relationships are based on the principle that objects have properties, and many times the value of the property is another object, which in turn also has properties. The object tree has branches because some of these properties are collection properties and hold more than one object, and the object tree has a root because the architecture ultimately must reference a single object that is the connection point to concepts that are outside the object tree (such as the browser host, or the Silverlight plug-in that displays the content).

Although there really is a single object tree in concept, the Silverlight API does not expose the full tree to you. A lot of the object tree structure is really implementation detail. Instead, you have object-specific properties that influence the child values of particular points in the tree, and that can report on the parent (in most cases the parent axis is read-only, because you typically build trees from the root up, either in code or through the process of XAML parsing). For example, a Panel has its Children property, which sets the child objects. FrameworkElement has Parent for reporting the parent. Both these APIs are on base classes, so they are available on a large number of Silverlight objects.

A related tree concept in Silverlight is the visual tree. The visual tree can be conceptualized as being an edited or filtered representation of the larger object tree. The filter applied is that only objects that have a rendering implication are present in the visual tree. For example, a collection class would not be part of the visual tree, and instead the visual tree abstracts collections into a "children" concept. However, the visual tree can also include objects that are not immediately apparent if you consider the loaded source XAML markup to be an approximation of the object tree. This is because the visual tree also reports objects that are the composited parts of controls that come from an applied control template, or that come from resource dictionaries. The visual tree is used internally for the Silverlight rendering process, but knowing something about the visual tree is often important for certain scenarios, such as writing or replacing a control template, or analysis of a control instance at run-time, after the template is applied. For these scenarios, Silverlight provides the VisualTreeHelper API that can examine the visual tree in a more generalized way than you could practically achieve with the object-specific parent and children properties.

The visual tree concept also exists in WPF, and the Silverlight concept of the visual tree is similar. A notable difference however is that WPF also provides an additional filter or conception of the object tree, known as the logical tree. The logical tree concept is relevant for certain property system behaviors. Silverlight does not expose this logical tree through a helper class. Some (but not all) of the relevant property behaviors do exist in Silverlight, but without a helper API to access it, the logical tree concept is not useful in Silverlight and thus is not discussed in the documentation. One minor compatibility implication of the logical tree omission is that the FrameworkElement..::.Parent property behavior is different in Silverlight version 3 and is actually reporting the visual tree parent.

Object Trees and XAML Markup

If you were to compare the object tree that is accessed through the Silverlight API and the tree shape of the XAML markup, they would not match exactly, node-for-node. This is because XAML is designed for markup, and ease of use during markup definition. For instance, XAML has the concept of a property element, which provides the guidance for which property is being set if one element is found nested within another. In the object tree, this would just look like a property on an object being set by another object. Conversely, XAML also has a concept of a content property, where the property being set is not even explicitly named in markup. And XAML has syntaxes that can either create objects based on string values of attributes, or provide references to objects that already exist but are defined elsewhere in the XAML markup, or are entirely external to the markup. Regardless of these minor inconsistencies, when you define a UI in XAML, you are defining the approximate structure of your eventual Silverlight object tree at run time.

For more information on the specific terminology and the rules for XAML, see XAML Overview.

Referencing Object Properties

Regardless of how you obtain an object reference from the Silverlight object tree, properties in the managed API are directly exposed through an object.property notation, related to the core concept of CLR properties in .NET. Underlying many of the Silverlight 2 properties is the concept of a dependency property. Dependency properties and the property system introduce some additional syntax possibilities for accessing properties other than by object.property, but other than for attached properties these are less commonly used and are not discussed in this topic. Dependency properties are discussed in detail in the topic Dependency Properties Overview.

Attached Properties in the Object Tree

Silverlight supports the concept of an attached property. From the perspective of the object tree, an attached property is a property that can be attached to any object in the tree, regardless of what type the object is (although in the Silverlight implementation, that object must at least be a dependency object). Attached property values exist in the object tree, but if you access them using code, you must use a different syntax than pure object.property notation. For details, see Attached Properties Overview.

Resources and Templates in the Object Tree

Silverlight supports a resource concept known as a resource dictionary. A resource dictionary is used to specify property values that require substantial sub-property settings themselves.

The most common scenario for the ResourceDictionary is to define ResourceDictionary elements in XAML, and then to use the defined resources as property values through XAML attributes, and the StaticResource markup extension. For some cases, the resource can be shared. For instance, you might define a LinearGradientBrush that contains multiple gradient stops in a ResourceDictionary, which you then apply to multiple Brush properties (potentially in UI that exists in different pages) in your visual design.

Templates operate by a somewhat different concept (whether defined in page-level or application-level resource dictionaries, in generic.xaml, or inline). The template itself is an object, but the template is potentially applied to the visual tree multiple times. Once applied, the elements in the template often use a TemplateBinding, which makes it possible to apply the template and still set specific values that are held by the templated object. The concepts behind templates are discussed in the topic Customizing the Appearance of an Existing Control by Using a ControlTemplate.

Traversing the Object Tree

Traversing the object tree (sometimes known colloquially as "walking the tree") is a common technique in object models. Traversing the tree means that you use properties that either reference child objects (typically these are collections) or parent relationships to a containing object (usually this is done from within a collection, and returns the collection itself). As a rough description of the process, you call a succession of child properties and parent properties, or perhaps helper methods, to navigate the axes of the object tree until you retrieve a value that contains the object that you were looking for.

As a general rule, you should be able to construct your content in XAML for Silverlight such that you do not need to query the structure of the tree extensively. To avoid the need to traverse the tree, give elements a value for the x:Name / Name attribute in the XAML markup that creates them. This creates an immediate reference that is available in the class that markup-compiles from the XAML, which is a much less error-prone technique for getting objects than traversing the tree.

Alternatively, if you are creating objects through code constructors rather than by XAML loading, you should be able to construct your code such that you have private fields or variables defined for retaining an object reference at run-time, either in a class, or stored as variables at an application level.

However, there are cases where it is not possible or practical to give an object a name and keep an object reference in scope. One such scenario is if you are adding dynamic content that is supplied by the user or by data binding, and you cannot predict the number of items added or the structure of the run time object tree. Another scenario is examining an applied template for a control, or a composited section of a control.

Caution noteCaution:

Silverlight in general supports the concept of skinning, or otherwise re-styling or re-templating a control. Particularly if you are a control author and are writing the support code for your control, it can be dangerous to assume a particular tree structure. Since most controls support a settable template (regardless of whether you have enabled more specific extension points such as sub-part styles) the run-time visual tree might be different than would be created by the applied default template. See Customizing the Appearance of an Existing Control by Using a ControlTemplate.

Try-catch Logic for Traversing "Children" and Other Collections

If your requirement for traversing the object tree involves finding objects that represent collections that would not be represented as part of the visual tree, you might need to write specialized functions that attempt to find APIs that match particular naming patterns or the object model of a particular class.

Walking the object tree downwards (away from the root) multiple levels is generally possible as long as you know the points at which the contained objects will have collections. You might have to use try/catch techniques or the equivalent to detect this, by checking whether Children exists and Count is nonzero (Children and Count here are placeholders and not literal APIs; Children and Count happen to be common names for these types of properties per the .NET naming guidelines, but the actual properties might have different names depending on the object and its object model). Some collections in the overall Silverlight object model are contained in properties that are not named Children. If you know you are walking into a particular collection property that is not named Children, you should account for this in your logic.

Using VisualTreeHelper

VisualTreeHelper is a utility class that can be useful for traversing the object tree. (The concept of the visual tree was explained earlier in the "Object Trees" section of this topic.)

Because you can operate on the visual tree at run time and traverse into the template parts, this can be a useful technique for examining template composition. Alternatively, you can examine a child collection that might be populated by data binding or where the full nature of the runtime object tree might not be fully known by your application code. You would do this by walking the tree through GetChild, using GetChildrenCount as the determinant of whether the tree node is a single item or a "Children" collection that you should iterate by the count.

Traversing into Template Content

Another technique besides VisualTreeHelper that is useful for traversing into template content is GetTemplateChild. Either using GetTemplateChild or traversing into template content is often necessary because the behavior of FindName is governed by the concept of a namescope. In this case, template content has a deliberately separate namescope from the rest of the object tree, because templates are shared and would otherwise cause name collisions when the template is applied more than once. GetTemplateChild finds objects by their template namescope x:Name values, working from the larger object tree scope of the particular Control where the template is applied.

For more information on the namescope concept, see XAML Namescopes.

Silverlight Objects and HTML DOM

There is also another object model available for scripting to HTML content: the HTML document object model (DOM). However, the DOM does not identify the content that is loaded by a Silverlight plug-in as being a full part of the DOM. For more information about the DOM and the distinction between the DOM and Silverlight object trees, see Silverlight Programming Models, XAML, and the HTML DOM.

JavaScript API

For more information about object trees using the JavaScript API, see JavaScript API for Silverlight.

See Also

Concepts

Tags :


Page view tracker