Vue d’ensemble des ressources XAML

Une ressource est un objet qui peut être réutilisé à différents endroits dans votre application. Des exemples de ressources comprennent des pinceaux et des styles. Cette vue d’ensemble explique comment utiliser des ressources dans XAML (Extensible Application Markup Language). Vous pouvez également créer et accéder aux ressources à l’aide du code.

Note

Les ressources XAML décrites dans cet article sont différentes des ressources d’application qui sont généralement des fichiers ajoutés à une application, telles que du contenu, des données ou des fichiers incorporés.

Utilisation de ressources en XAML

L’exemple suivant définit une SolidColorBrush en tant que ressource sur l’élément racine d’une page. L’exemple référence ensuite la ressource et l’utilise pour définir des propriétés de plusieurs éléments enfants, notamment un Ellipse, un TextBlocket un Button.

<Page Name="root"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
  <Page.Resources>
    <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
    <Style TargetType="Border" x:Key="PageBackground">
      <Setter Property="Background" Value="Blue"/>
    </Style>
    <Style TargetType="TextBlock" x:Key="TitleText">
      <Setter Property="Background" Value="Blue"/>
      <Setter Property="DockPanel.Dock" Value="Top"/>
      <Setter Property="FontSize" Value="18"/>
      <Setter Property="Foreground" Value="#4E87D4"/>
      <Setter Property="FontFamily" Value="Trebuchet MS"/>
      <Setter Property="Margin" Value="0,40,10,10"/>
    </Style>
    <Style TargetType="TextBlock" x:Key="Label">
      <Setter Property="DockPanel.Dock" Value="Right"/>
      <Setter Property="FontSize" Value="8"/>
      <Setter Property="Foreground" Value="{StaticResource MyBrush}"/>
      <Setter Property="FontFamily" Value="Arial"/>
      <Setter Property="FontWeight" Value="Bold"/>
      <Setter Property="Margin" Value="0,3,10,0"/>
    </Style>
  </Page.Resources>
  <StackPanel>
    <Border Style="{StaticResource PageBackground}">
      <DockPanel>
        <TextBlock Style="{StaticResource TitleText}">Title</TextBlock>
        <TextBlock Style="{StaticResource Label}">Label</TextBlock>
        <TextBlock DockPanel.Dock="Top" HorizontalAlignment="Left" FontSize="36" Foreground="{StaticResource MyBrush}" Text="Text" Margin="20" />
        <Button DockPanel.Dock="Top" HorizontalAlignment="Left" Height="30" Background="{StaticResource MyBrush}" Margin="40">Button</Button>
        <Ellipse DockPanel.Dock="Top" HorizontalAlignment="Left" Width="100" Height="100" Fill="{StaticResource MyBrush}" Margin="40" />
      </DockPanel>
    </Border>
  </StackPanel>
</Page>


Chaque élément au niveau de l’infrastructure (FrameworkElement ou FrameworkContentElement) a une propriété Resources, qui est un type ResourceDictionary qui contient des ressources définies. Vous pouvez définir des ressources sur n’importe quel élément, tel qu’un Button. Toutefois, les ressources sont le plus souvent définies sur l’élément racine, qui est Page dans l’exemple.

Chaque ressource d’un dictionnaire de ressources doit avoir une clé unique. Lorsque vous définissez des ressources dans le balisage, vous affectez la clé unique via la directive x :Key. En règle générale, la clé est une chaîne ; Toutefois, vous pouvez également le définir sur d’autres types d’objets à l’aide des extensions de balisage appropriées. Les clés non-chaînes pour les ressources sont utilisées par certaines zones de fonctionnalités dans WPF, notamment pour les styles, les ressources de composant et le style de données.

Vous pouvez utiliser une ressource définie avec la syntaxe d’extension de balisage de ressource qui spécifie le nom de clé de la ressource. Par exemple, utilisez la ressource comme valeur d’une propriété sur un autre élément.

<Button Background="{StaticResource MyBrush}"/>
<Ellipse Fill="{StaticResource MyBrush}"/>

Dans l’exemple précédent, lorsque le chargeur XAML traite la valeur {StaticResource MyBrush} pour la propriété Background sur Button, la logique de recherche de ressources vérifie d’abord le dictionnaire de ressources pour l’élément Button. Si Button n’a pas de définition de la clé de ressource MyBrush (dans cet exemple, sa collection de ressources est vide), la recherche vérifie ensuite l’élément parent de Button, qui est Page. Si vous définissez une ressource sur l’élément racine Page, tous les éléments de l’arborescence logique du Page peuvent y accéder. Et vous pouvez réutiliser la même ressource pour définir la valeur de n’importe quelle propriété qui accepte le même type que la ressource représente. Dans l’exemple précédent, la même ressource MyBrush définit deux propriétés différentes : la Background d’un Buttonet la Fill d’un Rectangle.

Ressources statiques et dynamiques

Une ressource peut être référencée comme statique ou dynamique. Les références sont créées en utilisant soit l'extension de balisage StaticResource , soit l'extension de balisage DynamicResource. Une extension de balisage est une fonctionnalité XAML qui vous permet de spécifier une référence d’objet en ayant l’extension de balisage traiter la chaîne d’attribut et renvoyer l’objet à un chargeur XAML. Pour plus d’informations sur le comportement de l’extension de balisage, consultez Extensions de balisage etXAML WPF.

Lorsque vous utilisez une extension de balisage, vous fournissez généralement un ou plusieurs paramètres sous forme de chaîne qui sont traités par cette extension de balisage particulière. La StaticResource Markup Extension traite une clé en recherchant la valeur de cette clé dans tous les dictionnaires de ressources disponibles. Le traitement se produit pendant le chargement, c’est-à-dire lorsque le processus de chargement doit affecter la valeur de propriété. L’extension de balisage DynamicResource traite plutôt une clé en créant une expression, et cette expression reste non évaluée tant que l’application n’est pas exécutée, à quel moment l’expression est évaluée et fournit une valeur.

Lorsque vous référencez une ressource, les considérations suivantes peuvent influencer si vous utilisez une référence de ressource statique ou une référence de ressource dynamique :

  • Lorsque vous déterminez la conception globale de la façon dont vous créez les ressources pour votre application (par page, dans l’application, en XAML libre ou dans un assembly resource-only), tenez compte des éléments suivants :

  • Fonctionnalité de l’application. La mise à jour des ressources en temps réel fait-elle partie des exigences de votre application ?

  • Comportement de recherche respectif de ce type de référence de ressource.

  • La propriété ou le type de ressource particulier et le comportement natif de ces types.

Ressources statiques

Les références de ressources statiques fonctionnent mieux pour les circonstances suivantes :

  • La conception de votre application concentre la plupart de ses ressources dans des dictionnaires de ressources au niveau de la page ou de l’application. Les références de ressources statiques ne sont pas réévaluées en fonction des comportements d’exécution, tels que le rechargement d’une page. Il peut donc y avoir un avantage en matière de performances pour éviter un grand nombre de références de ressources dynamiques lorsqu’elles ne sont pas nécessaires en fonction de la conception de votre ressource et de votre application.

  • Vous définissez la valeur d’une propriété qui n’est pas sur une DependencyObject ou une Freezable.

  • Vous créez un dictionnaire de ressources qui sera compilé dans une DLL et empaqueté dans le cadre de l’application ou partagé entre les applications.

  • Vous créez un thème pour un contrôle personnalisé et définissez des ressources utilisées dans les thèmes. Dans ce cas, vous ne souhaitez généralement pas le comportement de recherche de ressources dynamiques ; vous préférez plutôt le comportement de recherche de ressources statiques afin que la recherche soit prévisible et autonome au sein du thème. Avec une référence de ressource dynamique, même une référence au sein d’un thème est laissée non évaluée jusqu’au moment de l’exécution. et il est possible que lorsque le thème est appliqué, un élément local redéfinit une clé que votre thème tente de référencer, et l’élément local tombe avant le thème lui-même dans la recherche. Si cela se produit, votre thème ne se comporte pas comme prévu.

  • Vous utilisez des ressources pour définir un grand nombre de propriétés de dépendance. Les propriétés de dépendance ont une mise en cache de valeur effective activée par le système de propriétés. Par conséquent, si vous fournissez une valeur pour une propriété de dépendance qui peut être évaluée au moment du chargement, la propriété de dépendance n’a pas besoin de rechercher une expression réévaluée et peut retourner la dernière valeur effective. Cette technique peut être un avantage en matière de performances.

  • Vous souhaitez modifier la ressource sous-jacente pour tous les consommateurs ou conserver des instances accessibles en écriture distinctes pour chaque consommateur à l’aide de l'attribut x :Shared.

Comportement de recherche de ressources statiques

Le code suivant décrit le processus de recherche qui se produit automatiquement lorsqu’une ressource statique est référencée par une propriété ou un élément :

  1. Le processus de recherche vérifie la clé demandée dans le dictionnaire de ressources défini par l’élément qui définit la propriété.

  2. Le processus de recherche traverse ensuite l’arborescence logique vers le haut jusqu’à l’élément parent et son dictionnaire de ressources. Ce processus se poursuit jusqu’à ce que l’élément racine soit atteint.

  3. Les ressources d’application sont vérifiées. Les ressources d’application sont ces ressources dans le dictionnaire de ressources définie par l’objet Application pour votre application WPF.

Les références de ressources statiques d’un dictionnaire de ressources doivent faire référence à une ressource qui a déjà été définie lexicalement avant la référence de ressource. Les références futures ne peuvent pas être résolues par une référence de ressource statique. Pour cette raison, concevez la structure de votre dictionnaire de ressources de sorte que les ressources soient définies au début de chaque dictionnaire de ressources.

La recherche de ressources statiques peut s’étendre dans des thèmes ou dans des ressources système, mais cette recherche est prise en charge uniquement parce que le chargeur XAML reporte la requête. Le report est nécessaire afin que le thème d’exécution au moment du chargement de la page s’applique correctement à l’application. Toutefois, les références de ressources statiques aux clés connues pour exister uniquement dans les thèmes ou comme ressources système ne sont pas recommandées, car ces références ne sont pas réévaluées si le thème est modifié par l’utilisateur en temps réel. Une référence de ressource dynamique est plus fiable lorsque vous demandez des ressources de thème ou système. L’exception est lorsqu’un élément de thème lui-même demande une autre ressource. Ces références doivent être des références de ressources statiques, pour les raisons mentionnées précédemment.

Le comportement de l’exception si une référence de ressource statique n’est pas trouvée varie. Si la ressource a été différée, l’exception se produit au moment de l’exécution. Si la ressource n’a pas été différée, l’exception se produit au moment du chargement.

Ressources dynamiques

Les ressources dynamiques fonctionnent mieux quand :

  • La valeur de la ressource, y compris les ressources système ou celles définies par l’utilisateur, dépend de conditions qui ne sont pas connues tant que l’exécution n’a pas lieu. Par exemple, vous pouvez créer des valeurs setter qui font référence aux propriétés système telles qu’exposées par SystemColors, SystemFontsou SystemParameters. Ces valeurs sont vraiment dynamiques, car elles proviennent finalement de l’environnement d’exécution de l’utilisateur et du système d’exploitation. Vous pouvez également avoir des thèmes au niveau de l’application qui peuvent changer, où l’accès aux ressources au niveau de la page doit également capturer la modification.

  • Vous créez ou référencez des styles de thème pour un contrôle personnalisé.

  • Vous envisagez d’ajuster le contenu d’un ResourceDictionary pendant la durée de vie d’une application.

  • Vous disposez d’une structure de ressources complexe qui a des interdépendances, où une référence vers l’avant peut être nécessaire. Les références de ressources statiques ne prennent pas en charge les références anticipées, mais les références de ressources dynamiques les prennent en charge, car la ressource n'a pas besoin d'être évaluée avant l'exécution, rendant ainsi les références anticipées un concept non pertinent.

  • Vous référencez une ressource volumineuse du point de vue d’un ensemble de compilation ou de travail, et la ressource peut ne pas être utilisée immédiatement lorsque la page se charge. Les références de ressources statiques sont toujours chargées à partir du code XAML lorsque la page se charge. Toutefois, une référence de ressource dynamique ne se charge pas tant qu’elle n’est pas utilisée.

  • Vous créez un style dans lequel les valeurs setter peuvent provenir d’autres valeurs qui sont influencées par des thèmes ou d’autres paramètres utilisateur.

  • Vous appliquez des ressources à des éléments qui peuvent être réparés dans l’arborescence logique pendant la durée de vie de l’application. La modification du parent modifie également potentiellement l’étendue de recherche de ressources. Par conséquent, si vous souhaitez que la ressource d’un élément réparenté soit réévaluée en fonction de la nouvelle étendue, utilisez toujours une référence de ressource dynamique.

Comportement de recherche dynamique des ressources

Le comportement de recherche de ressources pour une référence de ressource dynamique met en parallèle le comportement de recherche dans votre code si vous appelez FindResource ou SetResourceReference:

  1. La recherche recherche la clé demandée dans le dictionnaire de ressources définie par l’élément qui définit la propriété :

  2. La recherche traverse l’arborescence logique vers le haut jusqu’à l’élément parent et son dictionnaire de ressources. Ce processus se poursuit jusqu’à ce que l’élément racine soit atteint.

  3. Les ressources d’application sont vérifiées. Les ressources d’application sont ces ressources dans le dictionnaire de ressources qui sont définies par l’objet Application pour votre application WPF.

  4. Le dictionnaire de ressources de thème est vérifié pour le thème actuellement actif. Si le thème change au moment de l’exécution, la valeur est réévaluée.

  5. Les ressources système sont vérifiées.

Le comportement des exceptions (le cas échéant) varie :

  • Si une ressource a été demandée par un appel FindResource et qu’elle n’a pas été trouvée, une exception est levée.

  • Si une ressource a été demandée par un appel TryFindResource et qu’elle n’a pas été trouvée, aucune exception n’est levée et la valeur retournée est null. Si la propriété définie n’accepte pas null, il est toujours possible qu’une exception plus grave soit levée, en fonction de la propriété individuelle définie.

  • Si une ressource a été demandée par une référence de ressource dynamique en XAML et qu’elle n’a pas été trouvée, le comportement dépend du système de propriétés général. Le comportement général est comme si aucune opération de paramètre de propriété ne s’est produite au niveau où la ressource existe. Par exemple, si vous tentez de définir l’arrière-plan sur un élément de bouton individuel à l’aide d’une ressource qui n’a pas pu être évaluée, aucune valeur n’est définie ; toutefois, la valeur effective peut toujours provenir d’autres composants du système de propriétés et de la hiérarchie des valeurs. Par exemple, la valeur d’arrière-plan peut toujours provenir d’un style de bouton défini localement ou du style de thème. Pour les propriétés qui ne sont pas définies par les styles de thème, la valeur effective après une évaluation de ressource ayant échoué peut provenir de la valeur par défaut dans les métadonnées de propriété.

Restrictions

Les références de ressources dynamiques ont des restrictions notables. Au moins l’une des conditions suivantes doit être remplie :

Étant donné que la propriété définie doit être une propriété DependencyProperty ou Freezable, la plupart des modifications de propriété peuvent se propager à l’interface utilisateur, car une modification de propriété (la valeur de ressource dynamique modifiée) est reconnue par le système de propriétés. La plupart des contrôles incluent la logique qui force une autre disposition d’un contrôle si un DependencyProperty change et que cette propriété peut affecter la disposition. Toutefois, toutes les propriétés qui ont une DynamicResource Markup Extension comme leur valeur ne sont pas garanties pour fournir des mises à jour en temps réel dans l'interface utilisateur. Cette fonctionnalité peut toujours varier en fonction de la propriété, ainsi que selon le type propriétaire de la propriété, ou même la structure logique de votre application.

Styles, DataTemplates et clés implicites

Bien que tous les éléments d’un ResourceDictionary doivent avoir une clé, cela ne signifie pas que toutes les ressources doivent avoir une x:Keyexplicite. Plusieurs types d’objets prennent en charge une clé implicite lorsqu’elles sont définies en tant que ressource, où la valeur de clé est liée à la valeur d’une autre propriété. Ce type de clé est appelé clé implicite, tandis qu’un attribut x:Key est une clé explicite. Vous pouvez remplacer n’importe quelle clé implicite en spécifiant une clé explicite.

Un scénario clé pour les ressources est celui où vous définissez un Style. En fait, une Style est presque toujours définie comme une entrée dans un dictionnaire de ressources, car les styles sont intrinsèquement destinés à être réutilisés. Pour plus d’informations sur la mise en forme et la modélisation, consultez Mise en forme et modélisation.

Les styles des contrôles peuvent être créés avec et référencés avec une clé implicite. Les styles de thème qui définissent l’apparence par défaut d’un contrôle reposent sur cette clé implicite. Du point de vue de la demande, la clé implicite est le Type du contrôle lui-même. Du point de vue de la définition des ressources, la clé implicite est la TargetType du style. Par conséquent, si vous créez des thèmes pour des contrôles personnalisés ou des styles qui interagissent avec des styles de thème existants, vous n'avez pas besoin de spécifier une directive x:Key pour cela Style. Et si vous souhaitez utiliser les styles thématiques, vous n’avez pas besoin de spécifier du tout de style. Par exemple, la définition de style suivante fonctionne, même si la ressource Style n’apparaît pas avoir de clé :

<Style TargetType="Button">
  <Setter Property="Background">
    <Setter.Value>
      <LinearGradientBrush>
        <GradientStop Offset="0.0" Color="AliceBlue"/>
        <GradientStop Offset="1.0" Color="Salmon"/>           
      </LinearGradientBrush>
    </Setter.Value>
  </Setter>  
  <Setter Property="FontSize" Value="18"/>
</Style>

Ce style a vraiment une clé : la clé implicite typeof(System.Windows.Controls.Button). Dans le balisage, vous pouvez spécifier un TargetType directement en tant que nom de type (ou vous pouvez éventuellement utiliser {x :Type...} pour renvoyer un Type.

Grâce aux mécanismes de style de thème par défaut utilisés par WPF, ce style est appliqué comme style d’exécution d’un Button sur la page, même si le Button lui-même n’essaie pas de spécifier sa propriété Style ou une référence de ressource spécifique au style. Votre style défini dans la page est placé plus haut dans la succession de recherche que celui du dictionnaire de thème, avec la même clé que celui-ci. Vous pouvez simplement spécifier <Button>Hello</Button> n’importe où dans la page, et le style que vous avez défini avec TargetType de Button s’appliquerait à ce bouton. Si vous le souhaitez, vous pouvez toujours définir explicitement le style avec la même valeur de type que TargetType pour plus de clarté dans votre balisage, mais cela est facultatif.

Les clés implicites pour les styles ne s’appliquent pas à un contrôle si OverridesDefaultStyle est true. (Notez également que OverridesDefaultStyle peut être défini dans le cadre du comportement natif de la classe de contrôle, plutôt que explicitement sur une instance du contrôle.) En outre, pour prendre en charge les clés implicites pour les scénarios de classe dérivée, le contrôle doit remplacer DefaultStyleKey (tous les contrôles existants fournis dans le cadre de WPF incluent ce remplacement). Pour plus d’informations sur les styles, les thèmes et la conception des contrôles, consultez Instructions pour la conception de contrôles stylables.

DataTemplate a également une clé implicite. La clé implicite d’un DataTemplate est la valeur de propriété DataType. DataType peut également être spécifié comme nom du type plutôt que explicitement à l’aide de {x :Type...}. Pour plus d’informations, consultez Vue d’ensemble de la création de modèles de données.

Voir aussi