Árboles en WPFTrees in WPF

En muchas tecnologías, los elementos y componentes se organizan en una estructura de árbol en la que los desarrolladores manipulan directamente los nodos de objeto en el árbol para modificar la representación o el comportamiento de una aplicación.In many technologies, elements and components are organized in a tree structure where developers directly manipulate the object nodes in the tree to affect the rendering or behavior of an application. Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) también usa varias metáforas de la estructura de árbol para definir las relaciones entre los elementos de programa.also uses several tree structure metaphors to define relationships between program elements. En su mayor parte, los desarrolladores de WPF pueden crear una aplicación en código o definir partes de la aplicación en código XAML mientras piensan conceptualmente en la metáfora de árbol de objetos, pero estarán llamando a una API concreta o usando un marcado concreto para llamarla, en lugar de usar una API de manipulación de árbol de objetos general como se usaría en DOM XML.For the most part WPF developers can create an application in code or define portions of the application in XAML while thinking conceptually about the object tree metaphor, but will be calling specific API or using specific markup to do so rather than some general object tree manipulation API such as you might use in XML DOM. WPF expone dos clases auxiliares que proporcionan una vista de metáfora de árbol, LogicalTreeHelper y VisualTreeHelper.WPF exposes two helper classes that provide a tree metaphor view, LogicalTreeHelper and VisualTreeHelper. Los términos árbol visual y árbol lógico también se usan en la documentación de WPF porque estos mismos árboles son útiles para entender el comportamiento de ciertas características clave de WPF.The terms visual tree and logical tree are also used in the WPF documentation because these same trees are useful for understanding the behavior of certain key WPF features. En este tema define lo que representan el árbol visual y árbol lógico, se describe cómo se relacionan estos árboles con un concepto de árbol de objetos general y presenta LogicalTreeHelper y VisualTreeHelpers.This topic defines what the visual tree and logical tree represent, discusses how such trees relate to an overall object tree concept, and introduces LogicalTreeHelper and VisualTreeHelpers.

Árboles en WPFTrees in WPF

La estructura de árbol más completa de WPFWPF es el árbol de objetos.The most complete tree structure in WPFWPF is the object tree. Si se define una página de aplicación en XAMLXAML y después se carga el XAMLXAML, se crea una estructura de árbol basada en las relaciones de anidamiento de los elementos del marcado.If you define an application page in XAMLXAML and then load the XAMLXAML, the tree structure is created based on the nesting relationships of the elements in the markup. Si se define una aplicación o una parte de la aplicación en código, se crea la estructura de árbol en función de cómo se asignen los valores de propiedad de las propiedades que implementan el modelo de contenido para un objeto determinado.If you define an application or a portion of the 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. En Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF), hay dos maneras de conceptualizar el árbol de objetos completo y de notificarlo a su API pública: como el árbol lógico y como el árbol visual.In Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF), there are two ways that the complete object tree is conceptualized and can be reported to its public API: as the logical tree and as the visual tree. Las distinciones entre árbol lógico y árbol visual no son siempre importantes, pero en ocasiones pueden dar lugar a problemas con algunos subsistemas de WPFWPF y afectar a las decisiones que se toman en el marcado o el código.The distinctions between logical tree and visual tree are not always necessarily important, but they can occasionally cause issues with certain WPFWPF subsystems and affect choices you make in markup or code.

Aunque no siempre se manipula directamente el árbol lógico o el árbol visual, entender los conceptos relativos a cómo interactúan ayuda a entender WPF como tecnología.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 useful for understanding WPF as a technology. Pensar en WPF como en un tipo de metáfora de árbol también es crucial para entender cómo funcionan la herencia de propiedades y el enrutamiento de eventos en WPFWPF.Thinking of WPF as a tree metaphor of some kind is also crucial to understanding how property inheritance and event routing work in WPFWPF.

Nota

Dado que el árbol de objetos es más un concepto que una API real, otra manera de pensar en el concepto es como un gráfico de objetos.Because the object tree is more of a concept than an actual API, another way to think of the concept is as an object graph. En la práctica, hay relaciones entre los objetos en tiempo de ejecución en las que la metáfora del árbol no servirá.In practice, there are relationships between objects at run time where the tree metaphor will break down. Pero la metáfora del árbol es lo bastante relevante para que la mayor parte de la documentación de WPF use el término árbol de objetos al hacer referencia a este concepto general, en especial con la interfaz de usuario definida en XAML.Nevertheless, particularly with XAML-defined UI, the tree metaphor is relevant enough that most WPF documentation will use the term object tree when referencing this general concept.

El árbol lógicoThe Logical Tree

En WPFWPF, el contenido se agrega a los elementos de la interfaz de usuario estableciendo propiedades de los objetos que respaldan esos elementos.In WPFWPF, you add content to UI elements by setting properties of the objects that back those elements. Por ejemplo, agrega elementos a un ListBox control mediante la manipulación de su Items propiedad.For example, you add items to a ListBox control by manipulating its Items property. Al hacerlo, se colocan elementos en el ItemCollection que es el Items valor de propiedad.By doing this, you are placing items into the ItemCollection that is the Items property value. De forma similar, para agregar objetos a un DockPanel, manipular su Children valor de propiedad.Similarly, to add objects to a DockPanel, you manipulate its Children property value. En este caso, se agregan objetos a la UIElementCollection.Here, you are adding objects to the UIElementCollection. Para obtener un ejemplo de código, vea Cómo: Agregar dinámicamente un elemento.For a code example, see How to: Add an Element Dynamically.

En Lenguaje XAML (Extensible Application Markup Language)Extensible Application Markup Language (XAML), al colocar los elementos de lista en un ListBox o controles u otros elementos de interfaz de usuario en un DockPanel, también usa el Items y Children propiedades, explícita o implícitamente, como en el ejemplo siguiente.In Lenguaje XAML (Extensible Application Markup Language)Extensible Application Markup Language (XAML), when you place list items in a ListBox or controls or other UI 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>

Si se procesara este código XAML como XML bajo un modelo de objetos de documento y se incluyeran como implícitas las etiquetas marcadas como comentario (lo que sería válido), el árbol DOM XML resultante incluiría elementos para <ListBox.Items> y los demás elementos implícitos.If you were to process this XAML as XML under a document object model, and if you had included the tags commented out as implicit (which would have been legal), then the resulting XML DOM tree would have included elements for <ListBox.Items> and the other implicit items. Pero XAML no se procesa de esta forma al leer el marcado y escribir en los objetos; el gráfico de objetos resultante no incluye literalmente ListBox.Items.But XAML does not process that way when you read the markup and write to objects, the resulting object graph does not literally include ListBox.Items. Pero tiene un ListBox propiedad denominada Items que contiene un ItemCollectiony que ItemCollection se ha inicializado pero puede estar vacío cuando el ListBox XAML se procesa.It does however have a ListBox property named Items that contains a ItemCollection, and that ItemCollection is initialized but empty when the ListBox XAML is processed. A continuación, cada elemento de objeto secundario que existe como contenido para el ListBox se agrega a la ItemCollection mediante llamadas del analizador a ItemCollection.Add.Then, each child object element that exists as content for the ListBox is added to the ItemCollection by parser calls to ItemCollection.Add. Este ejemplo de procesamiento de XAML en un árbol de objetos es hasta ahora aparentemente un ejemplo en el que el árbol de objetos creado es básicamente el árbol lógico.This example of processing XAML into an object tree is so far seemingly an example where the created object tree is basically the logical tree.

Pero el árbol lógico no es el gráfico de objetos completo que existe en tiempo de ejecución para la interfaz de usuario de la aplicación, incluso con los elementos de sintaxis implícitos de XAML factorizados. La razón principal para esto son los elementos visuales y las plantillas.However, the logical tree is not the entire object graph that exists for your application UI at run time, even with the XAML implicit syntax items factored out. The main reason for this is visuals and templates. Por ejemplo, considere la Button.For example, consider the Button. Los informes del árbol lógico del Button objeto y también su cadena Content.The logical tree reports the Button object and also its string Content. Pero este botón es más complejo en el árbol de objetos en tiempo de ejecución.But there is more to this button in the run-time object tree. En concreto, el botón sólo aparece en pantalla de la forma porque un determinado Button se aplicó la plantilla de control.In particular, the button only appears on screen the way it does because a specific Button control template was applied. Los objetos visuales que proceden de una plantilla aplicada (como definido por la plantilla Border de gris oscuro alrededor del botón visual) no se notifican en el árbol lógico, incluso si está buscando en el árbol lógico durante el tiempo de ejecución (como el control de un evento de entrada desde el interfaz de usuario visible y, a continuación, lee el árbol lógico).The visuals that come from an applied template (such as the template-defined Border of dark gray around the visual button) are not reported in the logical tree, even if you are looking at the logical tree during run time (such as handling an input event from the visible UI and then reading the logical tree). Para buscar los elementos visuales de la plantilla, sería necesario examinar el árbol visual en su lugar.To find the template visuals, you would instead need to examine the visual tree.

Para más información sobre cómo se asigna la sintaxis de XAMLXAML al gráfico de objetos creado, y la sintaxis implícita en XAML, vea Detalles de la sintaxis XAML o Información general sobre XAML (WPF).For more information about how XAMLXAML syntax maps to the created object graph, and implicit syntax in XAML, see XAML Syntax In Detail or XAML Overview (WPF).

Finalidad del árbol lógicoThe Purpose of the Logical Tree

El árbol lógico existe para que los modelos de contenido puedan iterar fácilmente sus posibles objetos secundarios y para que los modelos de contenido puedan ser extensibles.The logical tree exists so that content models can readily iterate over their possible child objects, and so that content models can be extensible. Además, el árbol lógico proporciona un marco para algunas notificaciones, como, por ejemplo cuándo se cargan todos los objetos en él.Also, the logical tree provides a framework for certain notifications, such as when all objects in the logical tree are loaded. Básicamente, el árbol lógico es una aproximación de un gráfico de objetos en tiempo de ejecución en el nivel de marco, que excluye los elementos visuales, pero es adecuado para muchas operaciones de consulta en la composición de su propia aplicación en tiempo de ejecución.Basically, the logical tree is an approximation of a run time object graph at the framework level, which excludes visuals, but is adequate for many querying operations against your own run time application's composition.

Además, las dos referencias de recursos estáticas y dinámicas se resuelven desplazándose hacia arriba por el árbol lógico para Resources colecciones en el objeto solicitante inicial y, a continuación, continuar con el árbol lógico y comprobar cada FrameworkElement (o FrameworkContentElement) por otro Resources valor que contiene un ResourceDictionary, que posiblemente contenga esa clave.In addition, both static and dynamic resource references are resolved by looking upwards through the logical tree for Resources collections on the initial requesting object, and then continuing up the logical tree and checking each FrameworkElement (or FrameworkContentElement) for another Resources value that contains a ResourceDictionary, possibly containing that key. El árbol lógico se usa para la búsqueda de recursos cuando también está presente el árbol visual.The logical tree is used for resource lookup when both the logical tree and the visual tree are present. Para más información sobre los diccionarios de recursos y la búsqueda, vea Recursos XAML.For more information on resource dictionaries and lookup, see XAML Resources.

Composición del árbol lógicoComposition of the Logical Tree

El árbol lógico se define en el marco de WPF, lo que significa que el elemento de base de WPF más pertinente para las operaciones del árbol lógico sea FrameworkElement o FrameworkContentElement.The logical tree is defined at the WPF framework-level, which means that the WPF base element that is most relevant for logical tree operations is either FrameworkElement or FrameworkContentElement. Sin embargo, como puede ver si realmente utiliza la LogicalTreeHelper API, el árbol lógico contiene a veces nodos que no son FrameworkElement o FrameworkContentElement.However, as you can see if you actually use the LogicalTreeHelper API, the logical tree sometimes contains nodes that are not either FrameworkElement or FrameworkContentElement. Por ejemplo, el árbol lógico notifica el Text valor de un TextBlock, que es una cadena.For instance, the logical tree reports the Text value of a TextBlock, which is a string.

Invalidar el árbol lógicoOverriding the Logical Tree

Los autores de controles avanzados pueden invalidar el árbol lógico si invalidan varias APIAPIs que definen la forma en que un objeto general o un modelo de contenido agrega o quita objetos en dicho árbol.Advanced control authors can override the logical tree by overriding several APIAPIs that define how a general object or content model adds or removes objects within the logical tree. Para obtener un ejemplo de cómo invalidar el árbol lógico, vea Invalidar el árbol lógico.For an example of how to override the logical tree, see Override the Logical Tree.

Herencia de valores de propiedadProperty Value Inheritance

La herencia de valores de propiedad funciona a través de un árbol híbrido.Property value inheritance operates through a hybrid tree. Los metadatos reales que contienen el Inherits propiedad que habilita la herencia de propiedad es el nivel de marco de WPF FrameworkPropertyMetadata clase.The actual metadata that contains the Inherits property that enables property inheritance is the WPF framework-level FrameworkPropertyMetadata class. Por lo tanto, el elemento primario que contiene el valor original y el objeto secundario que hereda ese valor deben ser FrameworkElement o FrameworkContentElement, y deben formar parte de un árbol lógico.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. Pero para las propiedades de WPF existentes que admiten la herencia de propiedades, la herencia del valor de propiedad puede perpetuarse a través de un objeto intermedio que no está en el árbol lógico.However, for existing WPF properties that support property inheritance, property value inheritance is able to perpetuate through an intervening object that is not in the logical tree. Esto es especialmente pertinente para hacer que los elementos de plantilla usen cualquier valor de propiedad heredado establecido en la instancia basada en una plantilla o en los niveles aun más altos de composición de página y, por tanto, superiores en el árbol lógico.Mainly this is relevant for having template elements use any inherited property values set either on the instance that is templated, or at still higher levels of page-level composition and therefore higher in the logical tree. Para que la herencia del valor de propiedad funcione de forma coherente a través de un límite de este tipo, la propiedad que hereda se debe registrar como una propiedad adjunta y se debe seguir este patrón si se piensa definir una propiedad de dependencia personalizada con un comportamiento de herencia de propiedades.In order for property value inheritance to work consistently across such a boundary, the inheriting property must be registered as an attached property, and you should follow this pattern if you intend to define a custom dependency property with property inheritance behavior. El árbol exacto que se usa para la herencia de propiedades no se puede prever completamente mediante un método de utilidad de clase del asistente, ni siquiera en tiempo de ejecución.The exact tree used for property inheritance cannot be entirely anticipated by a helper class utility method, even at run time. Para más información, vea Herencia de valores de propiedad.For more information, see Property Value Inheritance.

El árbol visualThe Visual Tree

Además del concepto de árbol lógico, en WPFWPF también existe el concepto de árbol visual.In addition to the concept of the logical tree, there is also the concept of the visual tree in WPFWPF. El árbol visual describe la estructura de objetos visuales, tal como está representada por la Visual clase base.The visual tree describes the structure of visual objects, as represented by the Visual base class. Cuando se escribe una plantilla para un control, se define o se vuelve a definir el árbol visual aplicable a ese control.When you write a template for a control, you are defining or redefining the visual tree that applies for that control. El árbol visual también tiene interés para los desarrolladores que quieren un control más específico sobre el dibujo por motivos de optimización y rendimiento.The visual tree is also of interest to developers who want lower-level control over drawing for performance and optimization reasons. Una exposición del árbol visual como parte de la programación convencional de aplicaciones de WPFWPF consiste en que las rutas de evento de un evento enrutado recorren en su mayoría el árbol visual, no el árbol lógico.One exposure of the visual tree as part of conventional WPFWPF application programming is that event routes for a routed event mostly travel along the visual tree, not the logical tree. Esta sutileza de comportamiento de los eventos enrutados puede no resultar patente de forma inmediata salvo para los autores de controles.This subtlety of routed event behavior might not be immediately apparent unless you are a control author. El enrutamiento de eventos a través del árbol visual permite que los controles que implementan la composición en el nivel visual controlen eventos o creen establecedores de eventos.Routing events through the visual tree enables controls that implement composition at the visual level to handle events or create event setters.

Árboles, elementos de contenido y hosts de contenidoTrees, Content Elements, and Content Hosts

Elementos de contenido (clases que derivan de ContentElement) no forman parte del árbol visual; no se heredan de Visual y no tienen una representación visual.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. Para que aparezca en una interfaz de usuario en absoluto, una ContentElement deben hospedarse en un host de contenido que es tanto un Visual y un participante en el árbol lógico.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. Normalmente, este tipo de objeto es un FrameworkElement.Usually such an object is a FrameworkElement. Puede considerarse el host del contenido como una especie de "explorador" para el contenido que decide cómo mostrar ese contenido dentro de la zona de la pantalla que controla.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. Cuando se hospeda el contenido, puede participar en algunos procesos del árbol que suelen asociarse al árbol visual.When the content is hosted, the content can be made a participant in certain tree processes that are normally associated with the visual tree. Por lo general, el FrameworkElement clase host incluye código de implementación que los hospedados agrega ContentElement a la ruta del evento a través de subnodos del árbol lógico de contenido, aunque el contenido hospedado no forme parte del verdadero árbol visual.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. Esto es necesario para que un ContentElement puede originar un evento enrutado que se enruta a cualquier elemento que no sea de sí mismo.This is necessary so that a ContentElement can source a routed event that routes to any element other than itself.

Exploración transversal del árbolTree Traversal

El LogicalTreeHelper clase proporciona el GetChildren, GetParent, y FindLogicalNode métodos para la exploración transversal del árbol lógico.The LogicalTreeHelper class provides the GetChildren, GetParent, and FindLogicalNode methods for logical tree traversal. En la mayoría de los casos, no debería tener que recorrer el árbol lógico de los controles existentes, porque casi siempre exponen sus elementos secundarios lógicos como una propiedad de colección dedicada que admite el acceso a colecciones como Add, un indexador, etc.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. Exploración transversal del árbol es principalmente un escenario que se usa por los autores de controles que optan por no derivar patrones de control previstos como ItemsControl o Panel donde ya están definidas las propiedades de la colección, y que desean proporcionar su propia colección compatibilidad con la propiedad.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.

El árbol visual también admite una clase auxiliar para la exploración transversal del árbol visual, VisualTreeHelper.The visual tree also supports a helper class for visual tree traversal, VisualTreeHelper. El árbol visual no se expone como cómodamente a través de las propiedades específicas del control, por lo que la VisualTreeHelper clase es la manera recomendada de recorrer el árbol visual si fuera necesario para su escenario de programación.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. Para más información, consulte Información general sobre la representación de gráficos en WPF.For more information, see WPF Graphics Rendering Overview.

Nota

A veces es necesario examinar el árbol visual de una plantilla aplicada.Sometimes it is necessary to examine the visual tree of an applied template. Se recomienda tener cuidado al usar esta técnica.You should be careful when using this technique. Aunque se esté recorriendo un árbol visual para un control donde se debe definir la plantilla, los consumidores del control siempre pueden cambiar la plantilla estableciendo el Template propiedad en las instancias e incluso el usuario final puede influir en la plantilla aplicada cambiando el tema del sistema.Even if you are traversing a visual tree for a control where you define the template, consumers of your control can always change the template by setting the Template property on instances, and even the end user can influence the applied template by changing the system theme.

Rutas para los eventos enrutados como un "árbol"Routes for Routed Events as a "Tree"

Como se ha mencionado antes, la ruta de cualquier evento enrutado determinado recorre una sola ruta de acceso predeterminada de un árbol, que es un híbrido de las representaciones del árbol visual y del árbol lógico.As mentioned before, the route of any given routed event travels along a single and predetermined path of a tree that is a hybrid of the visual and logical tree representations. La ruta de evento puede recorrer el árbol hacia arriba o hacia abajo en función de si es un evento enrutado de tunelización o de propagación.The event route can travel either in the up or down directions within the tree depending on whether it is a tunneling or bubbling routed event. El concepto de ruta de evento no tiene ninguna clase del asistente que lo respalde directamente y que se pueda usar para "recorrer" la ruta de evento con independencia de que se genere un evento que se enrute realmente.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. Hay una clase que representa la ruta, EventRoute, pero los métodos de esa clase suelen ser solo para uso interno.There is a class that represents the route, EventRoute, but the methods of that class are generally for internal use only.

Diccionarios de recursos y árbolesResource Dictionaries and Trees

La búsqueda de diccionarios de recursos para todos los Resources definidos en una página recorre básicamente el árbol lógico.Resource dictionary lookup for all Resources defined in a page traverses basically the logical tree. Los objetos que no están en el árbol lógico pueden hacer referencia a recursos con clave, pero la secuencia de búsqueda de recursos se inicia en el punto donde ese objeto está conectado al árbol lógico.Objects that are not in the logical tree can reference keyed resources, but the resource lookup sequence begins at the point where that object is connected to the logical tree. En WPF, solo los nodos de árbol lógico pueden tener un Resources propiedad que contiene un ResourceDictionary, por lo tanto, no hay ninguna ventaja en recorrer el árbol visual que busca recursos con clave desde un ResourceDictionary.In WPF, 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 keyed resources from a ResourceDictionary.

Pero la búsqueda de recursos también se puede extender más allá del árbol lógico inmediato.However, resource lookup can also extend beyond the immediate logical tree. Para el marcado de la aplicación, la búsqueda de recursos puede continuar con los diccionarios de recursos de nivel de aplicación y, después, con los valores de compatibilidad y sistema de tema a los que se hace referencia como propiedades estáticas o claves.For application markup, the resource lookup can then continue onward to application-level resource dictionaries and then to theme support and system values that are referenced as static properties or keys. Los propios temas también pueden hacer referencia a valores del sistema situados fuera del árbol lógico del tema si las referencias de recurso son dinámicas.Themes themselves can also reference system values outside of the theme logical tree if the resource references are dynamic. Para más información sobre los diccionarios de recursos y la lógica de búsqueda, vea Recursos XAML.For more information on resource dictionaries and the lookup logic, see XAML Resources.

Vea tambiénSee also