Références aux ressources ResourceDictionary et XAML

Vous pouvez définir l’IU ou les ressources de votre application à l’aide de XAML. Les ressources sont généralement des définitions d’un objet que vous prévoyez d’utiliser plusieurs fois. Pour faire référence à une ressource XAML ultérieurement, spécifiez une clé pour une ressource qui agira comme son nom. Vous pouvez référencer une ressource dans une application ou à partir d’une page XAML dans celle-ci. Vous pouvez définir vos ressources à l’aide d’un élément ResourceDictionary à partir du code XAML Windows Runtime. Vous pouvez ensuite référencer vos ressources à l’aide d’une extension de balisage StaticResource ou d’une extension de balisage ThemeResource.

Les éléments XAML que vous souhaiterez peut-être déclarer plus souvent que les ressources XAML incluent le style, le ControlTemplate, les composants d’animation et les sous-classes Brush. Ici, nous expliquons comment définir un ResourceDictionary et des ressources indexées, et comment les ressources XAML sont liées à d’autres ressources que vous définissez dans le cadre de votre application ou package d’application. Nous expliquons également les fonctionnalités avancées du dictionnaire de ressources telles que les MergedDictionaries et ThemeDictionaries.

Prérequis

Une bonne compréhension du balisage XAML. Nous vous recommandons de la Vue d’ensemble de XAML.

Définir et utiliser des ressources XAML

Les ressources XAML sont des objets qui sont référencés à partir d’un balisage multiple. Les ressources sont définies dans un ResourceDictionary, généralement dans un fichier distinct ou en haut de la page de balisage, comme ceci.

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <x:String x:Key="greeting">Hello world</x:String>
        <x:String x:Key="goodbye">Goodbye world</x:String>
    </Page.Resources>

    <TextBlock Text="{StaticResource greeting}" Foreground="Gray" VerticalAlignment="Center"/>
</Page>

Dans cet exemple :

  • <Page.Resources>…</Page.Resources> - Définit le dictionnaire de ressources.
  • <x:String> - Définit la ressource avec la clé « greeting ».
  • {StaticResource greeting}- Recherche la ressource avec la clé « greeting », qui est affectée à la propriété Text du composant TextBlock.

Remarque Ne confondez pas les concepts liés à ResourceDictionary et l’action de build Resource, les fichiers de ressources (.resw) ou d’autres « ressources » décrits dans le contexte de la structuration du projet de code qui produit votre package d’application.

Les ressources n’ont pas besoin d’être des chaînes : il peut s’agir de n’importe quel objet partageable, tel que les styles, les modèles, les pinceaux et les couleurs. Toutefois, les contrôles, les formes et d’autres FrameworkElements ne sont pas partageables et ne peuvent pas être déclarés comme des ressources réutilisables. Pour plus d’informations sur le partage, consultez la section Les ressources XAML doivent être partageables plus loin dans cette rubrique.

Ici, un pinceau et une chaîne sont déclarés en tant que ressources et utilisés par les contrôles d’une page.

<Page
    x:Class="SpiderMSDN.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <SolidColorBrush x:Key="myFavoriteColor" Color="green"/>
        <x:String x:Key="greeting">Hello world</x:String>
    </Page.Resources>

    <TextBlock Foreground="{StaticResource myFavoriteColor}" Text="{StaticResource greeting}" VerticalAlignment="Top"/>
    <Button Foreground="{StaticResource myFavoriteColor}" Content="{StaticResource greeting}" VerticalAlignment="Center"/>
</Page>

Toutes les ressources doivent avoir une clé. Généralement, cette clé est une chaîne définie avec x:Key="myString". Toutefois, il existe plusieurs autres façons de spécifier une clé :

  • Style et ControlTemplate nécessitent un composant TargetType, et utilisent le composant TargetType en tant que clé si x:Key n’est pas spécifié. Dans ce cas, la clé est l’objet Type réel, et non une chaîne. (Voir les exemples ci-dessous)
  • Les ressources DataTemplate qui ont un composant TargetType utilisent TargetType en tant que clé si x:Key n’est pas spécifié. Dans ce cas, la clé est l’objet Type réel, et non une chaîne.
  • x:Name peut être utilisé au lieu de x:Key. Cependant, x:Name génère également un champ code-behind pour la ressource. Par conséquent, x:Name est moins efficace que x:Key, car ce champ doit être initialisé lors du chargement de la page.

L’extension de balisage StaticResource peut récupérer des ressources uniquement avec un nom de chaîne (x:Key ou x:Name). Cependant, l’infrastructure XAML recherche également des ressources de style implicites (celles utilisant TargetType plutôt que x:Key ou x:Name) quand elle détermine le style et le modèle à utiliser pour un contrôle qui n’a pas défini les propriétés Style et ContentTemplate ou ItemTemplate.

Ici, le composant Style a une clé implicite de typeof(Button) et, dans la mesure où l’élément Button situé dans la partie inférieure de la page ne spécifie pas de propriété Style, il recherche un style avec une clé de typeof(Button) :

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <Style TargetType="Button">
            <Setter Property="Background" Value="Red"/>
        </Style>
    </Page.Resources>
    <Grid>
       <!-- This button will have a red background. -->
       <Button Content="Button" Height="100" VerticalAlignment="Center" Width="100"/>
    </Grid>
</Page>

Pour plus d’informations sur les styles implicites et leur fonctionnement, consultez Contrôles de style et Modèles de contrôle.

Rechercher des ressources dans le code

Vous accédez aux membres du dictionnaire de ressources comme pour n’importe quel autre dictionnaire.

Avertissement

Quand vous effectuez une recherche de ressource dans le code, seules les ressources dans le dictionnaire Page.Resources sont examinées. Contrairement à l’extension de balisage StaticResource, le code ne revient pas au dictionnaire Application.Resources si les ressources ne sont pas trouvées dans le premier dictionnaire.

 

Cet exemple montre comment récupérer la ressource redButtonStyle à partir du dictionnaire de ressources d’une page :

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <Style TargetType="Button" x:Key="redButtonStyle">
            <Setter Property="Background" Value="red"/>
        </Style>
    </Page.Resources>
</Page>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            Style redButtonStyle = (Style)this.Resources["redButtonStyle"];
        }
    }
    MainPage::MainPage()
    {
        InitializeComponent();
        Windows::UI::Xaml::Style style = Resources().TryLookup(winrt::box_value(L"redButtonStyle")).as<Windows::UI::Xaml::Style>();
    }

Pour rechercher des ressources à l’échelle de l’application à partir du code, utilisez Application.Current.Resources pour obtenir le dictionnaire de ressources de l’application, comme illustré ici.

<Application
    x:Class="MSDNSample.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:SpiderMSDN">
    <Application.Resources>
        <Style TargetType="Button" x:Key="appButtonStyle">
            <Setter Property="Background" Value="red"/>
        </Style>
    </Application.Resources>

</Application>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            Style appButtonStyle = (Style)Application.Current.Resources["appButtonStyle"];
        }
    }
    MainPage::MainPage()
    {
        InitializeComponent();
        Windows::UI::Xaml::Style style = Application::Current().Resources()
                                                               .TryLookup(winrt::box_value(L"appButtonStyle"))
                                                               .as<Windows::UI::Xaml::Style>();
    }

Vous pouvez également ajouter une ressource d’application dans le code.

Il y a deux choses à garder à l’esprit lors de cette opération.

  • Tout d’abord, vous devez ajouter les ressources avant qu’une page tente d’utiliser la ressource.
  • Ensuite, vous ne pouvez pas ajouter de ressources dans le constructeur de l’application.

Vous pouvez éviter ces deux problèmes si vous ajoutez la ressource dans la méthode Application.OnLaunched, comme ceci.

// App.xaml.cs
    
sealed partial class App : Application
{
    protected override void OnLaunched(LaunchActivatedEventArgs e)
    {
        Frame rootFrame = Window.Current.Content as Frame;
        if (rootFrame == null)
        {
            SolidColorBrush brush = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 0, 255, 0)); // green
            this.Resources["brush"] = brush;
            // … Other code that VS generates for you …
        }
    }
}
// App.cpp

void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
    Frame rootFrame{ nullptr };
    auto content = Window::Current().Content();
    if (content)
    {
        rootFrame = content.try_as<Frame>();
    }

    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (rootFrame == nullptr)
    {
        Windows::UI::Xaml::Media::SolidColorBrush brush{ Windows::UI::ColorHelper::FromArgb(255, 0, 255, 0) };
        Resources().Insert(winrt::box_value(L"brush"), winrt::box_value(brush));
        // … Other code that VS generates for you …

Chaque FrameworkElement peut avoir un ResourceDictionary

FrameworkElement est une classe de base dont les contrôles héritent et qui possède une propriété Resources. Vous pouvez donc ajouter un dictionnaire de ressources local à n’importe quel FrameworkElement.

Ici, la Page et la Bordure ont des dictionnaires de ressources, et elles ont toutes deux une ressource appelée « salutation ». L’élément TextBlock nommé « textBlock2 » est à l’intérieur de l’élément Border : sa recherche de ressources est donc exécutée dans un premier temps dans les ressources de Border, puis dans les ressources de Page et enfin dans les ressources de Application. Le TextBlock affiche « Hello World ».

Pour accéder aux ressources de cet élément à partir du code, utilisez la propriété Resources de cet élément. L’accès aux ressources d’un FrameworkElement dans le code, plutôt que dans le XAML, ne recherchera que dans ce dictionnaire, et non dans les dictionnaires de l’élément parent.

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <x:String x:Key="greeting">Hello world</x:String>
    </Page.Resources>
    
    <StackPanel>
        <!-- Displays "Hello world" -->
        <TextBlock x:Name="textBlock1" Text="{StaticResource greeting}"/>

        <Border x:Name="border">
            <Border.Resources>
                <x:String x:Key="greeting">Hola mundo</x:String>
            </Border.Resources>
            <!-- Displays "Hola mundo" -->
            <TextBlock x:Name="textBlock2" Text="{StaticResource greeting}"/>
        </Border>

        <!-- Displays "Hola mundo", set in code. -->
        <TextBlock x:Name="textBlock3"/>
    </StackPanel>
</Page>

    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            textBlock3.Text = (string)border.Resources["greeting"];
        }
    }
    MainPage::MainPage()
    {
        InitializeComponent();
        textBlock3().Text(unbox_value<hstring>(border().Resources().TryLookup(winrt::box_value(L"greeting"))));
    }

Dictionnaires de ressources fusionnés

Un dictionnaire de ressources fusionné combine un dictionnaire de ressources dans un autre, généralement dans un autre fichier.

Conseil Pour créer un fichier de dictionnaire de ressources dans Microsoft Visual Studio, utilisez l’option Ajouter > Nouvel élément… > Dictionnaire de ressources du menu Projet.

Ici, vous définissez un dictionnaire de ressources dans un fichier XAML distinct appelé Dictionary1.xaml.

<!-- Dictionary1.xaml -->
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MSDNSample">

    <SolidColorBrush x:Key="brush" Color="Red"/>

</ResourceDictionary>

Pour utiliser ce dictionnaire, vous le fusionnez avec le dictionnaire de votre page :

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml"/>
            </ResourceDictionary.MergedDictionaries>

            <x:String x:Key="greeting">Hello world</x:String>

        </ResourceDictionary>
    </Page.Resources>

    <TextBlock Foreground="{StaticResource brush}" Text="{StaticResource greeting}" VerticalAlignment="Center"/>
</Page>

Voici ce qui se passe dans cet exemple. Dans <Page.Resources>, vous déclarez <ResourceDictionary>. L’infrastructure XAML crée implicitement un dictionnaire de ressources pour vous lorsque vous ajoutez des ressources à <Page.Resources> ; toutefois, dans ce cas, vous ne voulez pas seulement un dictionnaire de ressources, vous voulez qu’un dictionnaire de ressources contienne des dictionnaires fusionnés.

Vous déclarez donc <ResourceDictionary>, puis ajoutez des éléments à sa collection <ResourceDictionary.MergedDictionaries>. Chacune de ces entrées prend la forme <ResourceDictionary Source="Dictionary1.xaml"/>. Pour ajouter plusieurs dictionnaires, ajoutez simplement une entrée <ResourceDictionary Source="Dictionary2.xaml"/> après la première entrée.

Après <ResourceDictionary.MergedDictionaries>…</ResourceDictionary.MergedDictionaries>, vous pouvez éventuellement placer des ressources supplémentaires dans votre dictionnaire principal. Vous utilisez les ressources d’un dictionnaire fusionné tout comme celles d’un dictionnaire normal. Dans l’exemple ci-dessus, {StaticResource brush} recherche la ressource dans le dictionnaire enfant/fusionné (Dictionary1.xaml), tandis que {StaticResource greeting} recherche sa ressource dans le dictionnaire de la page principale.

Dans la séquence de recherche de ressources, un dictionnaire MergedDictionaries est vérifié uniquement après la vérification de toutes les autres ressources indexées de ce ResourceDictionary. Après avoir recherché ce niveau, la recherche atteint les dictionnaires fusionnés, et chaque élément dans MergedDictionaries est vérifié. Si plusieurs dictionnaires fusionnés existent, ces dictionnaires sont vérifiés dans l’ordre dans lequel ils sont déclarés dans la propriété MergedDictionaries. Dans l’exemple suivant, si Dictionary2.xaml et Dictionary1.xaml ont déclaré la même clé, la clé de Dictionary2.xaml est utilisée en premier, car elle est la dernière dans le jeu MergedDictionaries.

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml"/>
                <ResourceDictionary Source="Dictionary2.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Page.Resources>

    <TextBlock Foreground="{StaticResource brush}" Text="greetings!" VerticalAlignment="Center"/>
</Page>

Dans l’étendue d’un ResourceDictionary, l’unicité de clé est vérifiée dans le dictionnaire. Toutefois, cette étendue ne s’étend pas sur différents éléments dans différents fichiers MergedDictionaries.

Vous pouvez utiliser la combinaison de la séquence de recherche et de l’absence d’application de clé unique dans les étendues de dictionnaire fusionné pour créer une séquence de valeurs de secours des ressources ResourceDictionary. Par exemple, vous pouvez stocker les préférences utilisateur pour une couleur de pinceau particulière dans le dernier dictionnaire de ressources fusionné dans la séquence, en utilisant un dictionnaire de ressources qui se synchronise avec les données d’état et de préférence utilisateur de votre application. Cependant, s’il n’existe encore aucune préférence utilisateur, vous pouvez définir cette même chaîne de clé pour une ressource ResourceDictionary dans le fichier MergedDictionaries initial et elle peut servir de valeur de secours. N’oubliez pas que toute valeur que vous fournissez dans un dictionnaire de ressources primaire est toujours vérifiée avant que les dictionnaires fusionnés ne soient vérifiés. Par conséquent, si vous souhaitez utiliser la technique de secours, ne définissez pas cette ressource dans un dictionnaire de ressources principal.

Ressources de thème et dictionnaires de thèmes

Une ThemeResource est similaire à une StaticResource, mais la recherche de ressources est réévaluée lorsque le thème change.

Dans cet exemple, vous définissez le premier plan d’un TextBlock sur une valeur du thème actuel.

<TextBlock Text="hello world" Foreground="{ThemeResource FocusVisualWhiteStrokeThemeBrush}" VerticalAlignment="Center"/>

Un dictionnaire de thème est un type spécial de dictionnaire fusionné qui contient les ressources qui varient avec le thème qu’un utilisateur utilise actuellement sur son appareil. Par exemple, le thème « clair » peut utiliser un pinceau de couleur blanche, tandis que le thème « sombre » peut utiliser un pinceau de couleur foncée. Le pinceau modifie la ressource vers laquelle il se résout, mais la composition d’un contrôle qui utilise le pinceau comme ressource peut être identique. Pour reproduire le comportement de basculement de thème dans vos propres modèles et styles, au lieu d’utiliser MergeDictionaries comme propriété pour fusionner des éléments dans les dictionnaires principaux, utilisez la propriété ThemeDictionaries.

Chaque élément ResourceDictionary dans ThemeDictionaries doit avoir une valeur x:Key. La valeur est une chaîne qui nomme le thème approprié, par exemple « ParDefaut », « Sombre », « Clair » ou « ContrasteEleve ». En règle générale, Dictionary1 et Dictionary2 définissent les ressources qui ont les mêmes noms, mais des valeurs différentes.

Ici, vous utilisez du texte rouge pour le thème clair et du texte bleu pour le thème sombre.

<!-- Dictionary1.xaml -->
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MSDNSample">

    <SolidColorBrush x:Key="brush" Color="Red"/>

</ResourceDictionary>

<!-- Dictionary2.xaml -->
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MSDNSample">

    <SolidColorBrush x:Key="brush" Color="blue"/>

</ResourceDictionary>

Dans cet exemple, vous définissez le premier plan d’un TextBlock sur une valeur du thème actuel.

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <ResourceDictionary>
            <ResourceDictionary.ThemeDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml" x:Key="Light"/>
                <ResourceDictionary Source="Dictionary2.xaml" x:Key="Dark"/>
            </ResourceDictionary.ThemeDictionaries>
        </ResourceDictionary>
    </Page.Resources>
    <TextBlock Foreground="{StaticResource brush}" Text="hello world" VerticalAlignment="Center"/>
</Page>

Pour les dictionnaires de thème, le dictionnaire actif à utiliser pour la recherche de ressources change de manière dynamique, à chaque fois que l’extension de balisage ThemeResource est utilisée pour faire la référence et que le système détecte une modification du thème. Le comportement de la recherche effectuée par le système est basé sur le mappage du thème actif à la x:Key d’un dictionnaire de thème spécifique.

Il peut être utile d’examiner la façon dont les dictionnaires de thèmes sont structurés dans les ressources de conception XAML par défaut, qui représente en parallèle les modèles utilisés par défaut par Windows Runtime pour ses contrôles. Ouvrez les fichiers XAML dans \(Program Files)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<version SDK>\Generic avec votre éditeur de texte ou votre IDE. Notez comment les dictionnaires de thème sont définis en premier dans generic.xaml et comment chaque dictionnaire de thème définit les mêmes clés. Chaque clé de ce type est ensuite référencée par des éléments de composition dans les différents éléments indexés qui se trouvent en dehors des dictionnaires de thèmes et définis plus loin dans le code XAML. Il existe également un fichier themeresources.xaml distinct pour la conception qui contient uniquement les ressources de thème et les modèles supplémentaires, et non les modèles de contrôle par défaut. Les zones de thème sont des doublons de ce que vous voyez dans generic.xaml.

Lorsque vous utilisez des outils de conception XAML pour modifier des copies de styles et de modèles, les outils de conception extraient des sections des dictionnaires de ressources de conception XAML et les placent en tant que copies locales d’éléments de dictionnaire XAML qui font partie de votre application et de votre projet.

Pour obtenir plus d’informations et une liste des ressources système et propres aux thèmes accessibles à votre application, consultez Ressources de thème XAML.

Comportement de recherche pour les références de ressources XAML

Comportement de recherche est le terme qui décrit la façon dont le système de ressources XAML tente de trouver une ressource XAML. La recherche se produit lorsqu’une clé est référencée en tant que référence de ressource XAML à partir d’un emplacement dans le code XAML de l’application. Tout d’abord, le système de ressources a un comportement prévisible pour l’endroit où il vérifie l’existence d’une ressource en fonction de l’étendue. Si une ressource n’est pas trouvée dans l’étendue initiale, l’étendue se développe. Le comportement de recherche se poursuit dans l’ensemble des emplacements et étendues où une ressource XAML peut éventuellement être définie par une application ou par le système. Si toutes les tentatives de recherche de ressources possibles échouent, une erreur se produit en général. Il est souvent possible d’éliminer ces erreurs pendant le processus de développement.

Le comportement de recherche des références de ressources XAML commence par l’objet où l’utilisation réelle est appliquée et par sa propre propriété Resources. S’il existe un ResourceDictionary à cet endroit, ce ResourceDictionary est consulté afin de vérifier s’il contient un élément avec la clé demandée. Ce premier niveau de recherche est rarement pertinent, car il est peu probable que vous définissiez puis référenciez une ressource sur le même objet. En fait, une propriété Resources n’existe pas souvent ici. Vous pouvez faire des références de ressources XAML depuis presque n’importe où en XAML ; vous n’êtes pas limité aux propriétés des sous-classes FrameworkElement.

La séquence de recherche vérifie ensuite l’objet parent suivant dans l’arborescence d’objets runtime de l’application. Si un FrameworkElement.Resources existe et contient un ResourceDictionary, l’élément de dictionnaire avec la chaîne de clé spécifiée est demandé. Si la ressource est trouvée, la séquence de recherche s’arrête et l’objet est fourni à l’emplacement où la référence a été effectuée. Sinon, le comportement de recherche passe au niveau parent suivant vers la racine de l’arborescence d’objets. La recherche continue de manière récursive vers le haut jusqu’à ce que l’élément racine du code XAML soit atteint, ce qui épuise la recherche de tous les emplacements de ressources immédiats possibles.

Remarque

Il est courant de définir toutes les ressources immédiates au niveau racine d’une page, à la fois pour tirer parti de ce comportement de recherche de ressource et par convention du style de balisage XAML.

Si la ressource demandée est introuvable dans les ressources immédiates, l’étape de recherche suivante consiste à vérifier la propriété Application.Resources. Application.Resources est le meilleur endroit pour placer toutes les ressources spécifiques à l’application qui sont référencées par plusieurs pages dans la structure de navigation de votre application.

Important

L’ordre des ressources ajoutées à ResourceDictionary affecte l’ordre dans lequel elles sont appliquées. Le dictionnaire XamlControlsResources remplace de nombreuses clés de ressources par défaut et doit donc être ajouté à Application.Resources d’abord afin qu’il ne remplace pas d’autres styles ou ressources personnalisés dans votre application.

Les modèles de contrôle ont un autre emplacement possible dans la recherche de référence : les dictionnaires de thèmes. Un dictionnaire de thèmes est un fichier XAML unique qui possède un élément ResourceDictionary comme racine. Le dictionnaire de thèmes peut être un dictionnaire fusionné à partir d’Application.Resources. Le dictionnaire de thèmes peut également être le dictionnaire de thèmes spécifique au contrôle pour un modèle de contrôle personnalisé.

Enfin, il existe une recherche de ressources par rapport aux ressources de la plateforme. Les ressources de plateforme incluent les modèles de contrôle définis pour chacun des thèmes de l’IU système et qui définissent l’apparence par défaut de tous les contrôles que vous utilisez pour l’IU dans une application Windows Runtime. Les ressources de plateforme incluent également un ensemble de ressources nommées, liées à l’apparence et aux thèmes à l’échelle du système. Ces ressources sont techniquement un élément MergedDictionaries, et elles sont donc disponibles pour la recherche à partir de XAML ou du code une fois l’application chargée. Par exemple, les ressources de thème système incluent une ressource nommée « SystemColorWindowTextColor » qui fournit une définition de couleur pour faire correspondre la couleur du texte de l’application à la couleur de texte d’une fenêtre système qui provient du système d’exploitation et des préférences utilisateur. D’autres styles XAML pour votre application peuvent faire référence à ce style, ou votre code peut obtenir une valeur de recherche de ressource (et la convertir en couleur dans notre exemple).

Pour obtenir plus d’informations et une liste des ressources système et propres aux thèmes accessibles à une application Windows en XAML, consultez Ressources de thème XAML.

Si la clé demandée est toujours introuvable dans tous ces emplacements, une erreur/exception d’analyse XAML se produit. Dans certaines circonstances, l’exception d’analyse XAML peut être une exception à l’exécution qui n’est pas détectée par une action de compilation de balisage XAML ou par un environnement de conception XAML.

En raison du comportement de recherche hiérarchisé pour les dictionnaires de ressources, vous pouvez définir délibérément plusieurs éléments de ressource qui ont chacun la même valeur de chaîne que la clé, tant que chaque ressource est définie à un niveau différent. En d’autres termes, bien que les clés soient uniques dans une ressource ResourceDictionary donnée, l’exigence d’unicité ne s’étend pas à la séquence de comportement de recherche dans son ensemble. Pendant la recherche, seul le premier objet récupéré avec succès est utilisé pour la référence de ressource XAML, puis la recherche s’arrête. Vous pouvez utiliser ce comportement pour demander la même ressource XAML par clé à différentes positions dans le code XAML de votre application mais vous pourrez récupérer des ressources différentes, en fonction de l’étendue à partir de laquelle la référence de ressource XAML a été effectuée et de la façon dont cette recherche particulière se comporte.

Références de transfert dans un ResourceDictionary

Les références de ressources XAML issues d’un dictionnaire de ressources particulier doivent référencer une ressource qui a déjà été définie avec une clé, et cette ressource doit apparaître sur le plan lexical avant la référence de ressource. Les références anticipées ne peuvent pas être résolues par une référence de ressource XAML. Pour cette raison, si vous utilisez des références de ressources XAML à partir d’une autre ressource, vous devez concevoir votre structure de dictionnaire de ressources afin que les ressources utilisées par d’autres ressources soient définies en premier dans un dictionnaire de ressources.

Les ressources définies au niveau de l’application ne peuvent pas faire référence à des ressources immédiates. Cela équivaut à tenter une référence de transfert, car les ressources de l’application sont réellement traitées en premier (au premier démarrage de l’application et avant le chargement d’un contenu de page de navigation). Toutefois, toute ressource immédiate peut faire référence à une ressource d’application, ce qui peut être une technique utile pour éviter les situations de référence de transfert.

Les ressources XAML doivent être partageables

Pour qu’un objet existe dans un ResourceDictionary, il doit être partageable.

Être partageable est obligatoire, car lorsque l’arborescence d’objets d’une application est construite et utilisée au moment de l’exécution, les objets ne peuvent pas exister à plusieurs emplacements de l’arborescence. En interne, le système de ressources crée des copies des valeurs de ressources à utiliser dans le graphe d'objets de votre application lorsque chaque ressource XAML est demandée.

Un ResourceDictionary, et un XAML Windows Runtime en général, prend en charge ces objets pour une utilisation partageable :

Vous pouvez également utiliser des types personnalisés comme ressource partageable si vous suivez les modèles d’implémentation nécessaires. Vous définissez ces classes dans votre code de stockage (ou dans les composants runtime que vous incluez), puis instanciez ces classes en XAML en tant que ressource. Les exemples sont des sources de données d’objet et des implémentations IValueConverter pour la liaison de données.

Les types personnalisés doivent avoir un constructeur par défaut, car c’est ce qu’utilise un analyseur XAML pour instancier une classe. Les types personnalisés utilisés en tant que ressources ne peuvent pas avoir la classe UIElement dans leur héritage, car une classe UIElement ne peut jamais être partagée (elle a toujours vocation à représenter exactement un seul élément d’interface utilisateur qui existe à une seule position dans le graphe d’objets de votre application d’exécution).

Étendue de l’utilisation de UserControl

Un élément UserControl a une situation particulière pour le comportement de recherche de ressources, car il a les concepts inhérents d’une étendue de définition et d’une étendue d’utilisation. Un UserControl qui fait une référence de ressource XAML à partir de son étendue de définition doit être en mesure de prendre en charge la recherche de cette ressource dans sa propre séquence de recherche d’étendue de définition ; autrement dit, il ne peut pas accéder aux ressources d’application. À partir d’une étendue d’utilisation UserControl, une référence de ressource est traitée comme étant dans la séquence de recherche vers sa racine de page d’utilisation (comme toute autre référence de ressource effectuée à partir d’un objet dans une arborescence d’objets chargée) et peut accéder aux ressources de l’application.

ResourceDictionary et XamlReader.Load

Vous pouvez utiliser un ResourceDictionary comme racine ou une partie de l’entrée XAML pour la méthode XamlReader.Load. Vous pouvez également inclure des références de ressources XAML dans ce XAML si toutes ces références sont entièrement autonomes dans le code XAML envoyé pour le chargement. XamlReader.Load analyse le code XAML dans un contexte qui ne tient compte d’aucun autre objet ResourceDictionary, pas même de Application.Resources. En outre, n’utilisez pas {ThemeResource} à partir du code XAML envoyé à XamlReader.Load.

Utilisation d’un ResourceDictionary à partir du code

La plupart des scénarios d’un ResourceDictionary sont gérés exclusivement en XAML. Vous déclarez le conteneur ResourceDictionary et les ressources au sein d’un fichier XAML ou d’un ensemble de nœuds XAML dans un fichier de définition d’interface utilisateur. Ensuite, vous utilisez des références de ressources XAML pour demander ces ressources à partir d’autres parties du code XAML. Toutefois, il existe certains scénarios où votre application peut vouloir ajuster le contenu d’un ResourceDictionary à l’aide du code qui s’exécute pendant l’exécution de l’application, ou au moins pour interroger le contenu d’un ResourceDictionary pour voir si une ressource est déjà définie. Ces appels de code étant effectués sur une instance de ResourceDictionary, vous devez d’abord extraire soit un ResourceDictionary immédiat quelque part dans l’arborescence d’objets en obtenant FrameworkElement.Resources, soit Application.Current.Resources.

Dans du code C # ou Microsoft Visual Basic, vous pouvez référencer une ressource dans un ResourceDictionary donné au moyen de l’indexeur (Item). Un ResourceDictionary est un dictionnaire indexé par chaîne. L’indexeur utilise donc la clé de chaîne au lieu d’un index entier. Dans les extensions de composant Visual C++ (C++/CX), utilisez Lookup.

Lorsque vous utilisez du code pour examiner ou modifier un ResourceDictionary, le comportement des API telles que Lookup ou Item ne passe pas par des ressources immédiates aux ressources d’application ; il s’agit d’un comportement d’analyseur XAML qui se produit uniquement lorsque des pages XAML sont chargées. Au moment de l’exécution, l’étendue des clés est autonome pour l’instance ResourceDictionary que vous utilisez au moment de l’utilisation. Toutefois, cette étendue s’étend dans MergedDictionaries.

Par ailleurs, si vous demandez une clé qui n’existe pas dans le ResourceDictionary, il se peut qu’aucune erreur ne soit générée et que la valeur fournie comme valeur de retour soit simplement null. Vous risquez toutefois d’obtenir une erreur si vous essayez d’utiliser la valeur null retournée en tant que valeur. L’erreur provient de la méthode setter de la propriété, et non de votre appel ResourceDictionary. La seule façon d’éviter une erreur est si la propriété a accepté null comme une valeur valide. Notez comment ce comportement contraste avec le comportement de recherche XAML au moment de l’analyse XAML ; un échec de résolution de la clé fournie à partir du code XAML au moment de l’analyse entraîne une erreur d’analyse XAML, même dans les cas où la propriété aurait pu accepter la valeur null.

Les dictionnaires de ressources fusionnés sont inclus dans l’étendue d’index du dictionnaire de ressources principal qui fait référence au dictionnaire fusionné au moment de l’exécution. Autrement dit, vous pouvez utiliser Item ou Lookup du dictionnaire principal pour rechercher des objets qui ont été définis dans le dictionnaire fusionné. Dans ce cas, le comportement de recherche ressemble au comportement de recherche XAML d’analyse : s’il existe plusieurs objets dans des dictionnaires fusionnés qui ont chacun la même clé, l’objet du dictionnaire ajouté en dernier est retourné.

Vous êtes autorisé à ajouter des éléments à un ResourceDictionary existant en appelant Ajouter (C # ou Visual Basic) ou Insérer (C++/CX). Vous pouvez ajouter les éléments aux ressources immédiates ou aux ressources d’application. L’un de ces appels d’API nécessite une clé, qui satisfait à l’exigence que chaque élément d’un ResourceDictionary doit avoir une clé. Toutefois, les éléments que vous ajoutez à un ResourceDictionary au moment de l’exécution ne sont pas pertinents pour les références de ressources XAML. La recherche nécessaire pour les références de ressources XAML se produit lorsque ce code XAML est d’abord analysé lorsque l’application est chargée (ou qu’une modification de thème est détectée). Les ressources ajoutées aux collections au moment de l’exécution n’étaient pas disponibles, et la modification du ResourceDictionary n’invalide pas une ressource déjà récupérée à partir de celle-ci même si vous modifiez la valeur de cette ressource.

Vous pouvez également supprimer des éléments d’un ResourceDictionary au moment de l’exécution, effectuer des copies de certains ou de tous les éléments ou d’autres opérations. La liste des membres pour ResourceDictionary indique quelles API sont disponibles. Dans la mesure où ResourceDictionary a une API projetée pour prendre en charge ses interfaces de collection sous-jacentes, vos options en matière d’API diffèrent selon que vous utilisez C # ou Visual Basic, ou bien C++/CX.

ResourceDictionary et localisation

Un ResourceDictionary XAML peut initialement contenir des chaînes qui doivent être localisées. Si c’est le cas, stockez ces chaînes en tant que ressources de projet au lieu d’un ResourceDictionary. Retirez les chaînes du code XAML et donnez plutôt à l’élément propriétaire une valeur de directive x:Uid. Ensuite, définissez une ressource dans un fichier de ressources. Fournissez un nom de ressource sous la forme XUIDValue.PropertyName et une valeur de ressource de la chaîne qui doit être localisée.

Recherche de ressources personnalisée

Pour les scénarios avancés, vous pouvez implémenter une classe qui peut avoir un comportement différent du comportement de recherche de référence de ressource XAML décrit dans cette rubrique. Pour ce faire, implémentez la classe CustomXamlResourceLoader. Vous pouvez ensuite accéder à ce comportement à l’aide de l’extension de balisage CustomResource pour les références de ressources au lieu d’utiliser StaticResource ou ThemeResource. La plupart des applications n’ont pas de scénarios qui nécessitent cela. Pour plus d’informations, consultez CustomXamlResourceLoader.