Arborescences dans WPF
Dans plusieurs technologies, les éléments et les composants sont organisés en arborescence dans laquelle les développeurs manipulent directement les nœuds d'objet dans l'arborescence pour modifier le rendu ou le comportement d'une application. Windows Presentation Foundation (WPF) utilise également plusieurs métaphores d'arborescence pour définir des relations entre les éléments d'un programme. Dans la plupart des cas, les développeurs WPF peuvent créer une application dans le code ou définir des parties de l'application en XAML en pensant conceptuellement à la métaphore de l'arborescence d'objets, mais en appelant l'API spécifique ou en utilisant un balisage spécifique pour ce faire, plutôt que des API de manipulation d'arborescence d'objets générales comme vous pouvez en utiliser en DOM XML. WPF expose deux classes de programme d'assistance qui fournissent une vue métaphorique de l'arborescence, LogicalTreeHelper et VisualTreeHelper. Les termes arborescence des éléments visuels et arborescence logique sont également utilisés dans la documentation WPF parce qu'ils sont utiles pour comprendre le fonctionnement de certaines fonctionnalités WPF clés. Cette rubrique définit ce que l'arborescence d'éléments visuels et l'arborescence logique représentent, explique la relation de ces arborescences avec le concept général d'arborescence d'objets et présente LogicalTreeHelper et VisualTreeHelper.
Cette rubrique comprend les sections suivantes.
- Arborescences dans WPF
- L'arborescence logique
- L'arborescence visuelle
- Arborescences, éléments de contenu et hôtes de contenu
- Parcours d'une arborescence
- Routes des événements routés sous la forme d'une "arborescence"
- Dictionnaires de ressources et arborescences
- Rubriques connexes
Arborescences dans WPF
L'arborescence la plus complète de WPF est l'arborescence d'objets. Si vous définissez une page d'application en XAML, puis chargez le XAML, l'arborescence est créée sur la base des relations d'imbrication des éléments dans les balises. Si vous définissez une application ou une portion d'application dans le code, l'arborescence est créée en fonction de la manière dont vous affectez les valeurs de propriété aux propriétés qui implémentent le modèle de contenu d'un objet donné. Dans Windows Presentation Foundation (WPF), l'arborescence d'objets complète est conceptualisée et peut être rapportée à son API publique de deux manières : en tant qu'arborescence logique et en tant qu'arborescence d'éléments visuels. Les distinctions entre arborescence logique et arborescence visuelle ne sont pas toujours nécessairement importantes, mais elles peuvent générer parfois des problèmes avec certains sous-systèmes WPF et affecter vos choix en terme de balisage ou de code.
Bien que vous ne manipuliez pas toujours directement l'arborescence logique ou l'arborescence d'éléments visuels, la compréhension des concepts d'interaction des arborescences permet de comprendre le fonctionnement de WPF en tant que technologie. Considérer WPF sous l'angle d'une métaphore d'arborescence est également crucial pour comprendre le fonctionnement de l'héritage des propriétés et du routage des événements dans WPF.
Remarque |
---|
L'arborescence d'objets étant plus un concept qu'une API réelle, une autre manière d'appréhender le concept consiste à la considérer comme un graphique d'objet.En pratique, il existe des relations entre les objets au moment de l'exécution au niveau desquelles la métaphore de l'arborescence ne sera pas appropriée.Néanmoins, en particulier avec une interface utilisateur définie en XAML, la métaphore de l'arborescence est suffisamment pertinente pour que la plupart de la documentation WPF utilise le terme d'arborescence d'objets pour faire référence à ce concept général. |
L'arborescence logique
Dans WPF, vous ajoutez le contenu aux éléments d'interface en définissant les propriétés des objets qui stockent ces éléments. Par exemple, vous ajoutez des éléments à un contrôle ListBox en manipulant sa propriété Items. Ainsi, vous placez des éléments dans la ItemCollection qui est la valeur de la propriété Items. De la même façon, pour ajouter des objets à un Children, vous manipulez sa valeur de propriété DockPanel. Ici, vous ajoutez des objets à la UIElementCollection. Pour obtenir un exemple de code, consultez Comment : ajouter dynamiquement un élément.
En Extensible Application Markup Language (XAML), lorsque vous placez des éléments de liste dans une ListBox, ou encore des contrôles ou d'autres éléments d'interface dans un DockPanel, vous utilisez également les propriétés Items et Children, soit explicitement soit implicitement, comme dans l'exemple suivant.
<DockPanel
Name="ParentElement"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://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 vous aviez voulu traiter ce XAML en tant que XML dans le cadre d'un modèle d'objet de document, et si vous aviez inclus les balises commentées comme étant implicites (ce qui aurait été légal), l'arborescence DOM XML obtenue aurait inclus les éléments de <ListBox.Items> et les autres éléments implicites. Or, XAML ne traite pas de cette manière lorsque vous lisez les balises et écrivez dans les objets, et le graphique d'objet obtenu n'inclut pas littéralement ListBox.Items. Il comporte en revanche une propriété ListBox nommée Items qui contient une ItemCollection, et cette ItemCollection est initialisée mais vide lorsque le XAML ListBox est traité. Ensuite, chaque élément d'objet enfant qui existe comme contenu pour la ListBox est ajouté à la ItemCollection par les appels de l'analyseur à ItemCollection.Add. Cet exemple du traitement de XAML dans une arborescence d'objets constitue un exemple dans lequel l'arborescence d'objets créée correspond en principe à l'arborescence logique.
Toutefois, l'arborescence logique n'est pas le graphique d'objet complet qui existe pour votre interface utilisateur d'application au moment de l'exécution, même si les éléments de syntaxe XAML explicite sont factorisés. Ceci est principalement dû aux visuels et aux modèles. Intéressons-nous par exemple au Button. L'arborescence logique signale l'objet Button et également sa chaîne Content. Toutefois, l'arborescence d'objets au moment de l'exécution contient d'autres éléments pour ce bouton. Plus particulièrement, le bouton s'affiche à l'écran de cette manière parce qu'un modèle de contrôle Button spécifique a été appliqué. Les visuels issus d'un modèle appliqué (tels que la Border gris sombre définie par le modèle autour du bouton visuel) ne sont pas signalés dans l'arborescence logique, même si vous regardez l'arborescence logique au moment de l'exécution (notamment la gestion d'un événement d'entrée de l'interface utilisateur visible suivie de la lecture de l'arborescence logique). Pour rechercher les visuels du modèle, vous devez à la place examiner l'arborescence d'éléments visuels.
Pour plus d'informations sur la correspondance entre la syntaxe XAML et le graphique d'objets créé et sur la syntaxe implicite en XAML, consultez Syntaxe XAML en détail ou Vue d'ensemble du langage XAML (WPF).
Fonction de l'arborescence logique
L'arborescence logique permet aux modèles de contenu d'itérer aisément au sein de leurs objets enfants possibles et de rendre les modèles de contenu extensibles. En outre, l'arborescence logique fournit une infrastructure pour certaines notifications, notamment dans le cas où tous les objets de l'arborescence logique sont chargés. Fondamentalement, l'arborescence logique est une approximation d'un graphique d'objets au moment de l'exécution au niveau de l'infrastructure qui exclut les visuels, mais convient pour bon nombre d'opérations d'interrogation sur la composition de votre propre application d'exécution.
De plus, les références à des ressources statiques et dynamiques sont résolues en recherchant les collections Resources en amont dans l'arborescence logique sur l'objet demandeur initial, puis en parcourant l'arborescence logique et en examinant chaque FrameworkElement (ou FrameworkContentElement) à la recherche d'une autre valeur Resources contenant un ResourceDictionary, et contenant éventuellement cette clé. L'arborescence logique est utilisée pour rechercher des ressources lorsque l'arborescence logique et l'arborescence visuelle sont présentes. Pour plus d'informations sur les dictionnaires de ressources et la recherche, consultez Vue d'ensemble des ressources.
Composition de l'arborescence logique
L'arborescence logique est défini au niveau de l'infrastructure WPF, ce qui signifie que l'élément de base WPF le plus pertinent pour les opérations d'arborescence logique est soit FrameworkElement, soit FrameworkContentElement. Toutefois, comme vous pouvez le voir si vous utilisez réellement l'API de LogicalTreeHelper, l'arborescence logique contient parfois des nœuds qui ne sont ni FrameworkElement, ni FrameworkContentElement. Par exemple, l'arborescence logique signale la valeur Text d'un TextBlock, qui est une chaîne.
Remplacement de l'arborescence logique
Les auteurs de contrôle avancés peuvent remplacer l'arborescence logique en remplaçant plusieurs APIs qui définissent la manière dont un objet général ou un modèle de contenu ajoute ou supprime des objets dans l'arborescence logique. Pour un exemple de remplacement de l'arborescence logique, consultez Comment : remplacer l'arborescence logique.
Héritage de la valeur de propriété
L'héritage de valeur de propriété fonctionne à travers une arborescence hybride. Les métadonnées qui contiennent la propriété Inherits qui active l'héritage de propriété sont la classe au niveau d'infrastructure WPF T:System.Windows.FrameworkPropertyMetadata. Par conséquent, le parent qui contient la valeur d'origine et l'objet enfant qui hérite de cette valeur doivent correspondre tous les deux à un FrameworkElement ou un FrameworkContentElement, et ces deux éléments doivent faire partie d'une arborescence logique. Toutefois, pour les propriétés WPF existantes qui prennent en charge l'héritage des propriétés, l'héritage des valeurs de propriété peut avoir lieu par le biais d'un objet intervenant ne figurant pas dans l'arborescence logique. Principalement, cela est pertinent pour que les éléments de modèle utilisent des valeurs de propriété héritées définies soit sur l'instance utilisée comme modèle, soit à des niveaux supérieurs de la composition de niveau page situés par conséquent plus haut dans l'arborescence logique. Pour que l'héritage de valeurs de propriété s'effectue de manière cohérente malgré cette limite, la propriété d'héritage doit être enregistrée en tant que propriété jointe et vous devez suivre ce modèle si vous envisagez de définir une propriété de dépendance personnalisée avec un comportement d'héritage de propriétés. L'arborescence exacte utilisée pour l'héritage de propriété ne peut pas être entièrement anticipée par une méthode d'utilitaire de classe d'assistance, même au moment de l'exécution. Pour plus d'informations, consultez Héritage de la valeur de propriété.
L'arborescence visuelle
Outre le concept de l'arborescence logique, il existe le concept d'arborescence visuelle dans WPF. L'arborescence d'éléments visuels décrit la structure des objets visuels, tels qu'ils sont représentés par la classe de base Visual. Lorsque vous écrivez un modèle pour un contrôle, vous définissez ou redéfinissez l'arborescence visuelle qui s'applique à ce contrôle. L'arborescence visuelle offre également un intérêt pour les développeurs qui veulent disposer d'un contrôle de niveau inférieur pour améliorer les performances et garantir l'optimisation. Un problème lié à l'arborescence d'éléments visuels dans le cadre de la programmation d'application WPF classique réside dans le fait que les routes d'un événement passent principalement par l'arborescence d'éléments visuels et non pas par l'arborescence logique. Cette subtilité de comportement d'événement routé peut ne pas être immédiatement évidente si vous n'êtes pas auteur de contrôle. Le routage des événements via l'arborescence d'éléments visuels permet aux contrôles qui implémentent la composition au niveau visuel de gérer les événements ou de créer des méthodes setter d'événement.
Arborescences, éléments de contenu et hôtes de contenu
Les éléments de contenu (classes qui dérivent de ContentElement) ne font pas partie de l'arborescence visuelle ; ils n'héritent pas de Visual et n'ont pas de représentation visuelle. Pour apparaître dans une interface utilisateur, un ContentElement doit être hébergé dans un hôte de contenu qui est à la fois un Visual et un élément d'arborescence logique. Habituellement, un tel objet est un FrameworkElement. Vous pouvez considérer que l'hôte de contenu ressemble à "navigateur" pour le contenu et choisit le mode d'affichage du contenu dans la zone d'écran que l'hôte contrôle. Lorsque le contenu est hébergé, il peut devenir un participant dans les certains processus d'arborescence associés normalement à l'arborescence visuelle. En général, la classe hôte FrameworkElement inclut le code d'implémentation qui ajoute tout ContentElement hébergé à la route d'événement via des sous-nœuds de l'arborescence logique de contenu bien que le contenu hébergé ne fasse pas partie de l'arborescence visuelle logique réelle. Vous devez procéder ainsi pour qu'une ContentElement puisse fournir la source d'un événement routé qui route vers tout autre élément que lui-même.
Parcours d'une arborescence
La classe LogicalTreeHelper fournit les méthodes GetChildren, GetParent et FindLogicalNode pour parcourir l'arborescence logique. Dans la plupart des cas, vous n'avez pas à parcourir l'arborescence logique des contrôles existants, parce que ces contrôles exposent presque toujours leurs éléments enfants logiques sous la forme d'une propriété de collection dédiée qui prend en charge l'accès à la collection, notamment Add, un indexeur, etc. Le parcours d'arborescence est principalement un scénario utilisé par les auteurs de contrôle qui choisissent de ne pas dériver depuis des modèles de contrôle prévus, tels que ItemsControl ou Panel où les propriétés de collection sont déjà définies, et qui veulent fournir leur propre support de propriété de collection.
L'arborescence visuelle prend en charge également une classe d'assistance pour le parcours d'arborescence visuelle, VisualTreeHelper. L'arborescence visuelle n'est pas exposée aussi aisément via des propriétés de contrôle. Par conséquent, la classe VisualTreeHelper est la méthode recommandée pour parcourir l'arborescence visuelle si cela est nécessaire dans votre scénario de programmation. Pour plus d'informations, consultez Vue d'ensemble du rendu graphique de WPF.
Remarque |
---|
Parfois, il est nécessaire d'examiner l'arborescence d'éléments visuels d'un modèle appliqué.Vous devez être prudent lors de l'utilisation de cette technique.Même si vous parcourez une arborescence d'éléments visuels d'un contrôle dans laquelle vous définissez le modèle, les utilisateurs de votre contrôle peuvent toujours modifier le modèle en définissant la propriété Template sur les instances, et même l'utilisateur final peut influencer le modèle appliqué en modifiant le thème du système. |
Routes des événements routés sous la forme d'une "arborescence"
Comme mentionné précédemment, l'itinéraire de tout événement routé passe par le chemin unique et prédéterminé d'une arborescence hybride composée des représentations de l'arborescence d'éléments visuels et de l'arborescence logique. Le parcours de l'événement peut s'effectuer vers le haut ou vers le bas dans l'arborescence, selon qu'il s'agit d'un événement routé de tunneling ou de propagation. Le concept de routage d'événement ne dispose pas d'une classe d'assistance directe qui pourrait être utilisée pour "parcourir" l'itinéraire d'événement indépendant du déclenchement d'un événement qui assure lui-même le routage. Il existe une classe qui représente la route, EventRoute, mais les méthodes de cette classe sont destinées généralement à une utilisation interne uniquement.
Dictionnaires de ressources et arborescences
La recherche dans le dictionnaire des ressources de toutes les Resources définies dans une page se fait généralement via l'arborescence logique. Les objets qui ne se trouvent pas dans l'arborescence logique peuvent faire référence à des ressources de clé, mais la séquence de recherche de ressources commence au niveau du point à partir duquel l'objet est connecté à l'arborescence logique. Dans WPF, seuls les nœuds d'arborescence logique peuvent avoir une propriété Resources qui contient un ResourceDictionary ; par conséquent, parcourir l'arborescence d'éléments visuels pour rechercher des ressources de clé d'un ResourceDictionary n'offre aucun avantage.
Toutefois, la recherche de ressources peut également s'étendre au delà de l'arborescence logique immédiate. Pour le balisage d'application, la recherche de ressources peut continuer ensuite vers l'avant dans les dictionnaires de ressources au niveau de l'application, puis dans les valeurs de prise en charge de thème et système référencées en tant que clés ou propriétés statiques. Les thèmes eux-mêmes peuvent également fait référence à des valeurs système en dehors de l'arborescence logique des thèmes si les références de ressources sont dynamiques. Pour plus d'informations sur les dictionnaires de ressources et la logique de recherche, consultez Vue d'ensemble des ressources.
Voir aussi
Concepts
Vue d'ensemble du rendu graphique de WPF
Vue d'ensemble des événements routés
Initialisation d'éléments objet ne figurant pas dans une arborescence d'objets