Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
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 del árbol para afectar a la representación o el comportamiento de una aplicación. Windows Presentation Foundation (WPF) también usa varias metáforas de estructura de árbol para definir relaciones entre elementos del programa. Para la mayor parte, los desarrolladores de WPF pueden crear una aplicación en el código o definir partes de la aplicación en XAML mientras piensan conceptualmente en la metáfora del árbol de objetos, pero llamarán a una API específica o usarán marcado específico para hacerlo en lugar de alguna API de manipulación de árbol de objetos general, como puede usar en XML DOM. WPF expone dos clases auxiliares que proporcionan una vista basada en la metáfora del árbol: LogicalTreeHelper y 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 comprender el comportamiento de determinadas características clave de WPF. En este tema se define lo que representa el árbol visual y el árbol lógico, se describe cómo se relacionan estos árboles con un concepto general de árbol de objetos e introduce LogicalTreeHelper y VisualTreeHelpers.
Árboles en WPF
La estructura de árbol más completa en WPF es el árbol de objetos. Si defines una página de aplicación en XAML y luego cargas el XAML, la estructura de árbol se crea en función de las relaciones de anidamiento de los elementos del marcado. Si define una aplicación o una parte de la aplicación en el código, la estructura de árbol se crea en función de cómo se asignan valores de propiedad para las propiedades que implementan el modelo de contenido para un objeto determinado. En WPF, hay dos maneras de conceptualizar el árbol de objetos completo y se puede notificar a su API pública: como árbol lógico y como árbol visual. Las diferencias entre árbol lógico y árbol visual no siempre son necesariamente importantes, pero en ocasiones pueden causar problemas con determinados subsistemas de WPF y afectar a las opciones que realice en el marcado o el código.
Aunque no siempre manipule el árbol lógico o el árbol visual directamente, comprender los conceptos de cómo interactúan los árboles es útil para comprender WPF como tecnología. Pensar en WPF como una metáfora de árbol de algún tipo también es fundamental para comprender cómo funcionan la herencia de propiedades y el enrutamiento de eventos en WPF.
Nota:
Dado que el árbol de objetos es más de un concepto que una API real, otra manera de pensar en el concepto es como un gráfico de objetos. En la práctica, hay relaciones entre objetos en tiempo de ejecución donde la metáfora del árbol dejará de ser efectiva. Sin embargo, especialmente con la interfaz de usuario definida por XAML, la metáfora del árbol es lo suficientemente relevante como para que la mayoría de la documentación de WPF use el término árbol de objetos al hacer referencia a este concepto general.
Árbol lógico
En WPF, se agrega contenido a los elementos de la interfaz de usuario estableciendo propiedades de los objetos que respaldan esos elementos. Por ejemplo, puede agregar elementos a un ListBox control manipulando su Items propiedad . Al hacerlo, coloca elementos en el ItemCollection, que es el valor de la propiedad Items. Del mismo modo, para agregar objetos a DockPanel, se manipula el valor de su propiedad Children. Aquí, va a agregar objetos al UIElementCollection. Para obtener un ejemplo de código, vea How to: Add an Element Dynamically.
En Lenguaje de Marcado Extensible de Aplicaciones (XAML), cuando colocas elementos de lista en un ListBox o controles u otros elementos de la interfaz de usuario en un DockPanel, también usas las propiedades Items y Children, ya sea de manera explícita o implícita, como en el ejemplo siguiente.
<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 fueras a procesar este XAML como XML en un modelo de objetos de documento y si hubieras incluido las etiquetas comentadas como implícitas (que habrían sido legales), el árbol XML DOM resultante habría incluido elementos para <ListBox.Items>
y los demás elementos implícitos. Pero XAML no procesa así al leer el marcado y escribir en objetos; el gráfico de objetos resultante no incluye ListBox.Items
literalmente. Sin embargo, tiene una ListBox propiedad denominada Items
que contiene un ItemCollectiony que ItemCollection se inicializa pero está vacío cuando se procesa el ListBox XAML. A continuación, cada elemento de objeto secundario que existe como contenido para ListBox se agrega a ItemCollection mediante llamadas del analizador a ItemCollection.Add
. Este ejemplo de procesamiento de XAML en un árbol de objetos es hasta ahora un ejemplo en el que el árbol de objetos creado es básicamente el árbol lógico.
Sin embargo, el árbol lógico no es el gráfico completo de objetos que existe para la interfaz de usuario de la aplicación en tiempo de ejecución, incluso excluyendo los elementos de sintaxis implícita XAML. La razón principal para esto son los elementos visuales y las plantillas. Por ejemplo, considere el Button. El árbol lógico notifica el Button objeto y también su cadena Content
. Pero hay más en este botón dentro del árbol de objetos en tiempo de ejecución. En concreto, el botón solo aparece en la pantalla como lo hace porque se aplicó una plantilla de control específica Button . Los objetos visuales que proceden de una plantilla aplicada (como la plantilla-definida Border de gris oscuro alrededor del botón visual) no se notifican en el árbol lógico, incluso si está viendo el árbol lógico durante el tiempo de ejecución (por ejemplo, manejar un evento de entrada desde la interfaz de usuario visible y luego leer el árbol lógico). Para buscar los objetos visuales de plantilla, en su lugar tendría que examinar el árbol visual.
Para obtener más información sobre cómo la sintaxis XAML se asigna al gráfico de objetos creado y la sintaxis implícita en XAML, consulta Sintaxis XAML en detalle o XAML en WPF.
Propósito del árbol lógico
El árbol lógico existe para que los modelos de contenido puedan iterar fácilmente sobre sus posibles objetos secundarios y para que los modelos de contenido puedan ser extensibles. Además, el árbol lógico proporciona un marco para determinadas notificaciones, como cuando se cargan todos los objetos del árbol lógico. 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 objetos visuales, pero es adecuado para muchas operaciones de consulta en la composición de su propia aplicación en tiempo de ejecución.
Además, las referencias de recursos estáticos y dinámicos se resuelven mirando hacia arriba a través del árbol lógico en Resources las colecciones del objeto de solicitud inicial y, a continuación, continuando en el árbol lógico y comprobando cada FrameworkElement (o FrameworkContentElement) para otro Resources
valor que contiene ResourceDictionary, posiblemente conteniendo esa clave. El árbol lógico se usa para la búsqueda de recursos cuando el árbol lógico y el árbol visual están presentes. Para obtener más información sobre los diccionarios de recursos y la búsqueda, consulta Recursos XAML.
Composición del árbol lógico
El árbol lógico se define en el nivel de marco de WPF, lo que significa que el elemento base de WPF más relevante para las operaciones de árbol lógico es FrameworkElement o FrameworkContentElement. Sin embargo, como puede ver si realmente usa la API LogicalTreeHelper, el árbol lógico a veces contiene nodos que no son ni FrameworkElement ni FrameworkContentElement. Por ejemplo, el árbol lógico informa del valor de un Text, que es una cadena.
Invalidación del árbol lógico
Los autores de controles avanzados pueden invalidar el árbol lógico invalidando varias API que definen cómo un modelo de contenido o objeto general agrega o quita objetos dentro del árbol lógico. Para obtener un ejemplo de cómo invalidar el árbol lógico, vea Invalidar el árbol lógico.
Herencia de valores de propiedad
La herencia de valores de propiedad funciona a través de un árbol híbrido. Los metadatos reales que contienen la propiedad Inherits que habilita la herencia de propiedades en el marco de trabajo de WPF son la clase a nivel de marco de trabajo FrameworkPropertyMetadata. Por lo tanto, tanto el elemento primario que contiene el valor original como el objeto secundario que hereda ese valor deben ser FrameworkElement o FrameworkContentElement, y ambos deben formar parte de algún árbol lógico. Sin embargo, para las propiedades de WPF existentes que admiten la herencia de propiedades, la herencia de valores de propiedad puede perpetuarse a través de un objeto intermedio que no está en el árbol lógico. Principalmente, esto es relevante para que los elementos de plantilla utilicen los valores de propiedades heredadas, ya sea establecidos en la instancia que tiene plantilla o en niveles aún más altos en la composición al nivel de la página, y por lo tanto más altos en el árbol lógico. Para que la herencia de valores de propiedad funcione de forma coherente en este límite, la propiedad heredada debe registrarse como una propiedad adjunta y debe seguir este patrón si tiene previsto definir una propiedad de dependencia personalizada con el comportamiento de herencia de propiedades. El árbol exacto usado para la herencia de propiedades no se puede prever completamente mediante un método de utilidad de clase auxiliar, incluso en tiempo de ejecución. Para obtener más información, vea Herencia de valores de propiedad.
Árbol visual
Además del concepto del árbol lógico, también existe el concepto del árbol visual en WPF. El árbol visual describe la estructura de los objetos visuales, como se representa mediante la Visual clase base. Al escribir una plantilla para un control, va a definir o redefinir el árbol visual que se aplica a ese control. El árbol visual también es de interés para los desarrolladores que desean un control de nivel inferior sobre el dibujo por motivos de rendimiento y optimización. Una exposición del árbol visual como parte de la programación convencional de aplicaciones WPF es que las rutas de eventos para un evento enrutado viajan principalmente a lo largo del árbol visual, no el árbol lógico. Esta sutileza del comportamiento de los eventos enrutados puede no ser inmediatamente aparente a menos que usted sea un desarrollador de controles. El enrutamiento de eventos a través del árbol visual permite a los controles que implementan la composición en el nivel visual para controlar eventos o crear establecedores de eventos.
Árboles, elementos de contenido y anfitriones de contenido
Los elementos de contenido (clases que derivan de ContentElement) no forman parte del árbol visual; no heredan de Visual y no tienen una representación visual. Para que aparezca en una interfaz de usuario, ContentElement debe hospedarse en un host de contenido que sea tanto un Visual como un participante del árbol lógico. Normalmente, este tipo de objeto es .FrameworkElement Puede conceptualizar que el host de contenido es similar a un "explorador" para el contenido y elige cómo mostrar ese contenido dentro de la región de pantalla que controla el host. Cuando se hospeda el contenido, el contenido se puede convertir en participante en determinados procesos de árbol que normalmente están asociados al árbol visual. Por lo general, la FrameworkElement clase host incluye código de implementación que agrega cualquier hospedado ContentElement a la ruta de eventos a través de subnodos del árbol lógico de contenido, aunque el contenido hospedado no forme parte del árbol visual verdadero. ContentElement es necesario para que pueda generar un evento enrutado que pueda enrutarse a cualquier elemento distinto a sí mismo.
Recorrido de árbol
La LogicalTreeHelper clase proporciona los GetChildrenmétodos , GetParenty FindLogicalNode para el recorrido de árbol lógico. En la mayoría de los casos, no debe tener que atravesar el árbol lógico de los controles existentes, ya que estos controles casi siempre exponen sus elementos secundarios lógicos como una propiedad de colección dedicada que admite el acceso a la colección, como Add
, un indexador, etc. El recorrido de árbol es principalmente un escenario que utilizan los autores de controles que eligen no derivar de patrones de control previstos, como ItemsControl o Panel, donde ya están definidas las propiedades de colección, y que tienen la intención de proporcionar su propio soporte para propiedades de colección.
El árbol visual también admite una clase auxiliar para recorrer el árbol visual, VisualTreeHelper. El árbol visual no se expone tan convenientemente a través de propiedades específicas del control, por lo que la clase VisualTreeHelper es la manera recomendada de recorrer el árbol visual si es necesario en su escenario de programación. Para obtener más información, vea Información general sobre la representación de gráficos de WPF.
Nota:
A veces es necesario examinar el árbol visual de una plantilla aplicada. Debe tener cuidado al usar esta técnica. Incluso si estás atravesando un árbol visual para un control donde defines la plantilla, los usuarios de tu control siempre pueden cambiar la plantilla estableciendo la propiedad Template en las instancias, e incluso el usuario final puede influir en la plantilla aplicada cambiando el tema del sistema.
Rutas de eventos enrutados como un "árbol"
Como se mencionó antes, cualquier evento enrutado viaja por un camino único y predeterminado en un árbol que es un híbrido de las representaciones visuales y lógicas. La ruta de evento puede viajar en las direcciones ascendentes o descendentes dentro del árbol en función de si se trata de un evento enrutado de tunelización o de propagación. El concepto de ruta de evento no tiene una clase auxiliar que sea directamente compatible y que pueda usarse para recorrer la ruta del evento sin tener que generar un evento que realmente enruta. Hay una clase que representa la ruta, , EventRoutepero los métodos de esa clase son generalmente solo para uso interno.
Diccionarios de recursos y árboles
La búsqueda de diccionario de recursos para todas las Resources
definidas en una página recorre básicamente el árbol lógico. Los objetos que no están en el árbol lógico pueden hacer referencia a los recursos con clave, pero la secuencia de búsqueda de recursos comienza en el punto donde ese objeto está conectado al árbol lógico. En WPF, solo los nodos de árbol lógico pueden tener una Resources
propiedad que contenga un ResourceDictionary elemento, por lo tanto, no tiene sentido recorrer el árbol visual buscando recursos con clave de un ResourceDictionary.
Sin embargo, la búsqueda de recursos también puede extenderse más allá del árbol lógico inmediato. Para la marcación de la aplicación, la búsqueda de recursos puede continuar con los diccionarios de recursos de nivel de aplicación y, a continuación, a los diccionarios de recursos de nivel de tema y luego a los valores del sistema, que se hacen referencia como propiedades estáticas o claves. Los propios temas también pueden hacer referencia a valores del sistema fuera del árbol lógico del tema si las referencias de recursos son dinámicas. Para obtener más información sobre los diccionarios de recursos y la lógica de búsqueda, consulta Recursos XAML.
Consulte también
.NET Desktop feedback