ResourceDictionary- und XAML-Ressourcenreferenzen

Sie können die Benutzeroberfläche oder Ressourcen für Ihre App mithilfe von XAML definieren. Ressourcen sind in der Regel Definitionen eines Objekts, das Sie mehr als einmal verwenden möchten. Um später auf eine XAML-Ressource zu verweisen, geben Sie einen Schlüssel für eine Ressource an, der wie ihr Name fungiert. Sie können auf eine Ressource innerhalb einer App oder von einer beliebigen XAML-Seite in dieser darauf verweisen. Ressourcen können mithilfe eines ResourceDictionary-Elements aus der Windows-Runtime-XAML definiert werden. Anschließend können Sie auf Ihre Ressourcen verweisen, indem Sie eine StaticResource-Markuperweiterung oder ThemeResource-Markuperweiterung verwenden.

Zu den XAML-Elementen, die besonders häufig als XAML-Ressourcen deklariert werden, zählen Style, ControlTemplate, Animationskomponenten und Brush-Unterklassen. Hier erläutern wir die Definition von ResourceDictionary-Elementen und Schlüsselressourcen sowie den Bezug von XAML-Ressourcen zu anderen Ressourcen, die Sie als Teil Ihrer App oder Ihres App-Pakets definieren. Außerdem werden die erweiterten Features des Ressourcenverzeichnisses wie etwa MergedDictionaries und ThemeDictionaries beschrieben.

Voraussetzungen

Ein solides Verständnis von XAML-Markups. Es wird empfohlen, die XAML-Übersicht zu lesen.

Definieren und Verwenden von XAML-Ressourcen

XAML-Ressourcen sind Objekte, auf die aus Markup mehr als einmal verwiesen wird. Ressourcen werden üblicherweise in einer separaten Datei oder oben auf der Markupseite in einem ResourceDictionary-Element wie hier definiert.

<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>

In diesem Beispiel:

  • <Page.Resources>…</Page.Resources> – Definiert das Ressourcenverzeichnis.
  • <x:String> – Definiert die Ressource mit dem Schlüssel „greeting“.
  • {StaticResource greeting} – Sucht nach der Ressource mit dem Schlüssel „greeting“, die der Text-Eigenschaft von TextBlock zugeordnet ist.

Hinweis Die Konzepte für ResourceDictionary dürfen nicht mit dem Buildvorgang Resource, mit Ressourcendateien (.resw) oder mit anderen Ressourcen verwechselt werden, die im Zusammenhang mit der Strukturierung des Codeprojekts zur Generierung Ihres App-Pakets erwähnt werden.

Ressourcen müssen keine Zeichenketten sein. sie können ein beliebiges gemeinsam nutzbares Objekt sein, z. B. Stile, Vorlagen, Pinsel und Farben. Steuerelemente, Formen und andere FrameworkElement-Elemente können allerdings nicht freigegeben und somit auch nicht als wiederverwendbare Ressourcen deklariert werden. Weitere Informationen zur Freigabe finden Sie weiter unten in diesem Thema im Abschnitt XAML-Ressourcen müssen freigabefähig sein.

Hier werden sowohl ein Pinsel als auch eine Zeichenkette als Ressourcen deklariert und von Steuerelementen auf einer Seite verwendet.

<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>

Alle Ressourcen müssen über einen Schlüssel verfügen. In der Regel handelt es sich bei diesem Schlüssel um eine mit x:Key="myString" definierte Zeichenkette. Es gibt jedoch einige andere Möglichkeiten zum Angeben eines Schlüssels:

  • Style und ControlTemplate erfordern ein TargetType-Element. TargetType wird als Schlüssel verwendet, wenn x:Key nicht angegeben ist. In diesem Fall ist der Schlüssel das tatsächliche Type-Objekt, keine Zeichenkette. (Siehe Beispiele unten)
  • Für DataTemplate-Ressourcen mit TargetType wird das TargetType-Element als Schlüssel verwendet, wenn x:Key nicht angegeben ist. In diesem Fall ist der Schlüssel das tatsächliche Type-Objekt, keine Zeichenkette.
  • x:Name kann anstelle von x:Key verwendet werden. „x:Name“ generiert jedoch auch ein CodeBehind-Feld für die Ressource. Daher ist „x:Name“ weniger effizient als „x:Key“, da dieses Feld beim Laden der Seite initialisiert werden muss.

Die StaticResource-Markuperweiterung kann Ressourcen nur mit einem Zeichenkettennamen (x:Key oder x:Name) abrufen. Das XAML-Framework sucht aber auch nach impliziten Stilressourcen (für die TargetType verwendet wird, anstatt x:Key oder x:Name), wenn entschieden wird, welcher Stil und welche Vorlage für ein Steuerelement verwendet werden sollen, für das die Eigenschaften Style und ContentTemplate oder ItemTemplate nicht festgelegt wurden.

Hier verfügt Style über den impliziten Schlüssel typeof(Button). Da für das Button-Steuerelement unten auf der Seite keine Style-Eigenschaft angegeben ist, wird nach einem Stil mit dem Schlüssel typeof(Button) gesucht:

<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>

Weitere Informationen zu impliziten Stilen und deren Funktionsweise finden Sie unter Formatieren von Steuerelementen und Steuerelementvorlagen.

Nachschlagen von Ressourcen im Code

Sie greifen wie für jedes andere Verzeichnis auf Mitglieder des Ressourcenverzeichnisses zu.

Warnung

Wenn Sie im Code eine Ressourcensuche durchführen, werden nur die Ressourcen im Page.Resources-Verzeichnis berücksichtigt. Im Gegensatz zur StaticResource-Markuperweiterung fällt der Code nicht auf das Application.Resources-Verzeichnis zurück, wenn die Ressourcen nicht im ersten Verzeichnis gefunden werden.

 

In diesem Beispiel wird gezeigt, wie Sie die redButtonStyle-Ressource aus dem Ressourcenverzeichnis einer Seite abrufen:

<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>();
    }

Um appweite Ressourcen aus Code nachzuschlagen, verwenden Sie Application.Current.Resources, um das Ressourcenverzeichnis der App abzurufen, wie hier gezeigt.

<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>();
    }

Sie können auch eine Anwendungsressource im Code hinzufügen.

Es gibt zwei Dinge, die Sie bei dieser Vorgehensweise beachten sollten.

  • Erstens müssen Sie die Ressourcen hinzufügen, bevor eine Seite versucht, die Ressource zu verwenden.
  • Zweitens können Sie keine Ressourcen im Konstruktor der App hinzufügen.

Sie können beide Probleme vermeiden, wenn Sie die Ressource wie folgt in der Application.OnLaunched-Methode hinzufügen.

// 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 …

Jedes FrameworkElement kann über ein ResourceDictionary verfügen

FrameworkElement ist eine Basisklasse zum Steuern der Vererbung, und sie verfügt über eine Resources-Eigenschaft. Sie können also jedem FrameworkElement ein lokales Ressourcenverzeichnis hinzufügen.

Hier verfügen sowohl das Page-Element als auch das Border-Element über Ressourcenwörterbücher, und beide Elemente weisen eine Ressource mit dem Namen „greeting“ auf. Das TextBlock-Element namens „textBlock2“ ist im Border-Element enthalten. Der dazugehörige Ressourcenverweis sucht also zuerst nach den Ressourcen des Border-Elements, anschließend nach den Ressourcen des Page-Elements und zuletzt nach den Ressourcen des Application-Elements. Im TextBlock steht dann „Hola mundo“.

Verwenden Sie die Resources-Eigenschaft dieses Elements, um über den Code auf die Ressourcen dieses Elements zuzugreifen. Beim Zugreifen auf die Ressourcen eines FrameworkElement-Elements im Code anstatt per XAML, wird nur im entsprechenden Verzeichnis gesucht, nicht in den Verzeichnissen des übergeordneten Elements.

<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"))));
    }

Zusammengeführte Ressourcenwörterbücher

Ein zusammengeführtes Ressourcenverzeichnis integriert ein Ressourcenverzeichnis in ein anderes, in der Regel in einer anderen Datei.

Tipp In Microsoft Visual Studio können Sie eine Ressourcenverzeichnisdatei erstellen, indem Sie im Menü Projekt die Option Neues >-Element hinzufügen… >-Ressourcenverzeichnis verwenden.

Hier definieren Sie ein Ressourcenverzeichnis in einer separaten XAML-Datei mit dem Namen „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>

Um dieses Verzeichnis zu verwenden, führen Sie es mit dem Verzeichnis Ihrer Seite zusammen:

<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>

Dies geschieht in diesem Beispiel. In <Page.Resources> deklarieren Sie <ResourceDictionary>. Das XAML-Framework erstellt implizit ein Ressourcenverzeichnis für Sie, wenn Sie Ressourcen zu <Page.Resources> hinzufügen. In diesem Fall möchten Sie jedoch nicht irgendein Ressourcenverzeichnis, sondern eines, das zusammengeführte Verzeichnisse enthält.

Also deklarieren Sie <ResourceDictionary> und fügen dann Elemente zu seiner <ResourceDictionary.MergedDictionaries>-Sammlung hinzu. Jeder dieser Einträge ist in der Form <ResourceDictionary Source="Dictionary1.xaml"/>. Wenn Sie mehr als ein Verzeichnis hinzufügen möchten, fügen Sie einfach einen <ResourceDictionary Source="Dictionary2.xaml"/>-Eintrag nach dem ersten Eintrag hinzu.

Nach <ResourceDictionary.MergedDictionaries>…</ResourceDictionary.MergedDictionaries> können Sie optional zusätzliche Ressourcen in Ihr Hauptverzeichnis einfügen. Sie verwenden Ressourcen aus einem zusammengeführten Verzeichnis wie ein normales Verzeichnis. Im obigen Beispiel findet {StaticResource brush} die Ressource im untergeordneten/zusammengeführten Wörterbuch (Dictionary1.xaml), während {StaticResource greeting} die Ressource im Hauptseitenverzeichnis findet.

In der Ressourcensuchsequenz wird ein MergedDictionaries-Verzeichnis nur nach erfolgter Überprüfung aller anderen Schlüsselressourcen des ResourceDictionary überprüft. Nach dem Durchsuchen dieser Ebene erreicht die Suche die zusammengeführten Verzeichnisse und jedes Element in MergedDictionaries wird überprüft. Wenn mehrere zusammengeführte Verzeichnisse vorhanden sind, werden diese Verzeichnisse in umgekehrter Reihenfolge eingecheckt, in der sie in der MergedDictionaries-Eigenschaft deklariert werden. Wenn im folgenden Beispiel sowohl „Dictionary2.xaml“ als auch „Dictionary1.xaml“ denselben Schlüssel deklariert haben, wird der Schlüssel aus „Dictionary2.xaml“ zuerst verwendet, da er im MergedDictionaries-Satz zuletzt steht.

<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>

Innerhalb des Bereichs eines ResourceDictionary wird das Verzeichnis auf die Eindeutigkeit der Schlüssel überprüft. Dieser Bereich erstreckt sich jedoch nicht über verschiedene Elemente in MergedDictionaries-Dateien.

Sie können die Kombination aus Suchsequenz und fehlender Erzwingung eindeutiger Schlüssel für Bereiche mit zusammengeführten Verzeichnissen verwenden, um eine Fallbackwertesequenz von ResourceDictionary-Ressourcen zu erstellen. Sie können z. B. Benutzereinstellungen für eine bestimmte Pinselfarbe im letzten zusammengeführten Ressourcenverzeichnis in der Sequenz speichern, indem Sie ein Ressourcenverzeichnis verwenden, das mit den Status- und Benutzereinstellungsdaten Ihrer App synchronisiert wird. Wenn jedoch noch keine Benutzereinstellungen vorhanden sind, können Sie dieselbe Schlüsselzeichenfolge für eine ResourceDictionary-Ressource in der ursprünglichen MergedDictionaries-Datei definieren. Diese kann als Fallbackwert verwendet werden. Denken Sie daran, dass jeder Wert, den Sie in einem primären Ressourcenverzeichnis angeben, immer überprüft wird, bevor die zusammengeführten Wörterbücher überprüft werden. Wenn Sie also die Fallbacktechnik verwenden möchten, definieren Sie diese Ressource nicht in einem primären Ressourcenverzeichnis.

Designressourcen und Designverzeichnisse

Eine ThemeResource ähnelt einer StaticResource, aber die Ressourcensuche wird neu ausgewertet, wenn sich das Design ändert.

In diesem Beispiel legen Sie den Vordergrund eines TextBlock-Elements auf einen Wert aus dem aktuellen Design fest.

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

Ein Designverzeichnis ist eine spezielle Art eines zusammengeführten Verzeichnisses, das die Ressourcen enthält, die mit dem Design variieren, das ein Benutzer derzeit auf seinem Gerät verwendet. Das Design „hell“ kann z. B. einen weißen Pinsel verwenden, während das Design „dunkel“ einen dunklen Pinsel verwenden kann. Der Pinsel ändert die Ressource, in die er aufgelöst wird, ansonsten kann die Zusammensetzung eines Steuerelements, das den Pinsel als Ressource verwendet, jedoch identisch sein. Um das Designwechselverhalten in Ihren eigenen Vorlagen und Stilen zu reproduzieren, müssen Sie, anstatt diese Elemente mit MergedDictionaries als Eigenschaft in den Hauptverzeichnissen zusammenzuführen, die ThemeDictionaries-Eigenschaft verwenden.

Hierbei muss jedes ResourceDictionary-Element in ThemeDictionaries über einen x:Key-Wert verfügen. Der Wert ist eine Zeichenkette, die das relevante Design benennt, z. B. „Default“, „Dark“, „Light“ oder „HighContrast“. In der Regel definieren Dictionary1 und Dictionary2 Ressourcen, die dieselben Namen aber unterschiedliche Werte aufweisen.

Hier verwenden Sie roten Text für das helle Design und blauen Text für das dunkle Design.

<!-- 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>

In diesem Beispiel legen Sie den Vordergrund eines TextBlock-Elements auf einen Wert aus dem aktuellen Design fest.

<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>

Bei Designverzeichnissen ändert sich das aktive Wörterbuch, das für die Ressourcensuche verwendet werden soll, dynamisch, immer wenn ThemeResource-Markuperweiterung verwendet wird, um den Verweis zu erstellen, und das System eine Designänderung erkennt. Das vom System durchgeführte Suchverhalten basiert auf der Zuordnung des aktiven Designs zum x:Key eines bestimmten Designverzeichnisses.

Es kann hilfreich sein, die Art und Weise zu untersuchen, wie die Designverzeichnisse in den standardmäßigen XAML-Designressourcen strukturiert sind, die den Vorlagen entsprechen, die von der Windows-Runtime standardmäßig für ihre Steuerelemente verwendet werden. Öffnen Sie die XAML-Dateien in „\(Programmdateien)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<SDK-Version>\Generic“ mit einem Text-Editor oder Ihrer IDE. Beachten Sie, wie die Designverzeichnisse zuerst in generic.xaml definiert werden und wie jedes Designverzeichnis die gleichen Schlüssel definiert. Jeder dieser Schlüssel wird dann von Elementen der Anordnung in den verschiedenen mit Schlüssel versehenen Elementen referenziert, die sich außerhalb der Designverzeichnisse befinden und später im XAML-Code definiert sind. Es gibt auch eine separate themeresources.xaml-Datei für Design, die nur die Designressourcen und zusätzlichen Vorlagen enthält, nicht die Standardsteuerelementvorlagen. Die Designbereiche sind Duplikate davon, was in generic.xaml angezeigt würde.

Wenn Sie XAML-Designtools zum Bearbeiten von Kopien von Stilen und Vorlagen verwenden, extrahieren die Designtools Abschnitte aus den XAML-Designressourcenverzeichnissen und platzieren sie als lokale Kopien von XAML-Verzeichniselementen, die Teil Ihrer App und Ihres Projekts sind.

Weitere Informationen und eine Liste der verfügbaren designspezifischen Ressourcen sowie Systemressourcen für Ihre App finden Sie unter XAML-Designressourcen.

Suchverhalten für XAML-Ressourcenverweise

Suchverhalten ist der Begriff, der beschreibt, wie das XAML-Ressourcensystem versucht, eine XAML-Ressource zu finden. Die Suche erfolgt, wenn auf einen Schlüssel von einer beliebigen Stelle im XAML-Code der App als XAML-Ressourcenverweis verwiesen wird. Zunächst verfügt das Ressourcensystem über ein vorhersehbares Verhalten für den Ort, an dem überprüft wird, ob eine Ressource auf der Grundlage des Bereichs vorhanden ist. Wenn eine Ressource im anfänglichen Bereich nicht gefunden wird, wird der Bereich erweitert. Das Suchverhalten wird an allen Speicherorten und Bereichen fortgesetzt, für die eine XAML-Ressource möglicherweise von einer App oder vom System definiert werden kann. Wenn alle möglichen Ressourcensuchversuche fehlschlagen, ist oft ein Fehler das Ergebnis. Es ist in der Regel möglich, diese Fehler während des Entwicklungsprozesses zu beseitigen.

Das Suchverhalten für XAML-Ressourcenverweise beginnt mit dem Objekt, bei dem die tatsächliche Verwendung angewendet wird, und mit dessen eigener Resources-Eigenschaft. Wenn dort ein ResourceDictionary vorhanden ist, wird dieses ResourceDictionary auf ein Element überprüft, das den angeforderten Schlüssel enthält. Diese erste Suchebene ist selten relevant, da Sie normalerweise keine Ressource für dasselbe Objekt definieren und dann darauf verweisen. Tatsächlich gibt es hier häufig keine Resources-Eigenschaft. Sie können XAML-Ressourcenverweise nahezu überall in XAML erstellen. Dabei sind Sie nicht auf Eigenschaften von FrameworkElement-Unterklassen beschränkt.

Die Suchsequenz überprüft dann das nächste übergeordnete Objekt in der Laufzeitobjektstruktur der App. Wenn eine FrameworkElement.Resources-Eigenschaft vorhanden ist und ein ResourceDictionary enthält, wird das Verzeichniselement mit der angegebenen Schlüsselzeichenfolge angefordert. Wenn die Ressource gefunden wird, wird die Suchsequenz beendet und das Objekt wird an der Position bereitgestellt, an der der Verweis erstellt wurde. Andernfalls wechselt das Suchverhalten zur nächsten übergeordneten Ebene in Richtung der Wurzeln der Objektstruktur. Die Suche wird rekursiv nach oben fortgesetzt, bis das Stammelement des XAML-Codes erreicht ist, was die Suche aller möglichen unmittelbaren Ressourcenspeicherorte erschöpfend abschließt.

Hinweis

Es ist üblich, alle direkten Ressourcen auf Stammebene einer Seite zu definieren, um sowohl die Vorteile dieses Ressourcensuchverhaltens zu nutzen als auch eine Konvention des XAML-Markupstils einzuhalten.

Wenn die angeforderte Ressource in den direkten Ressourcen nicht gefunden werden kann, besteht der nächste Schritt bei der Suche in der Überprüfung der Application.Resources-Eigenschaft. Application.Resources ist der beste Ort, um appspezifische Ressourcen zu platzieren, auf die von mehreren Seiten in der Navigationsstruktur Ihrer App verwiesen wird.

Wichtig

Die Reihenfolge der Ressourcen, die einem ResourceDictionary hinzugefügt werden, wirkt sich auf die Reihenfolge aus, in der sie angewendet werden. Das XamlControlsResources-Wörterbuch überschreibt viele Standardressourcenschlüssel und sollte daher zuerst zu Application.Resources hinzugefügt werden, damit keine anderen benutzerdefinierten Stile oder Ressourcen in der App überschrieben werden.

Steuerelementvorlagen haben einen anderen möglichen Speicherort in der Verweissuche: Designverzeichnisse. Bei einem Designverzeichnis handelt es sich um eine einzelne XAML-Datei mit einem ResourceDictionary-Element als Stamm. Bei einem Designverzeichnis kann es sich um ein zusammengeführtes Verzeichnis aus Application.Resources handeln. Das Designverzeichnis kann auch das steuerelementspezifische Designverzeichnis für ein benutzerdefiniertes Steuerelement mit Vorlagen sein.

Schließlich gibt es eine Ressourcensuche für Plattformressourcen. Plattformressourcen enthalten die Steuerelementvorlagen, die für jedes der System-UI-Designs definiert sind und die die Standarddarstellung aller Steuerelemente definieren, die Sie für die Benutzeroberfläche in einer Windows-Runtime-App verwenden. Plattformressourcen enthalten auch eine Reihe benannter Ressourcen, die sich auf systemweite Darstellung und Designs beziehen. Diese Ressourcen sind aus technischer Sicht ein MergedDictionaries-Element und daher nach dem Laden der App für die XAML- oder Codesuche verfügbar. Die Systemdesignressourcen enthalten z. B. eine Ressource mit dem Namen „SystemColorWindowTextColor“, die eine Color-Definition zum Abgleichen einer App-Textfarbe mit der Textfarbe eines Systemfensters bereitstellt, die vom Betriebssystem und den Benutzereinstellungen stammt. Andere XAML-Stile für Ihre App können auf diesen Stil verweisen, oder Ihr Code kann einen Ressourcensuchwert abrufen (und im Beispielfall in Color umwandeln).

Weitere Informationen und eine Liste der verfügbaren designspezifischen Ressourcen sowie Systemressourcen für eine Windows-App, die XAML verwendet, finden Sie unter XAML-Designressourcen.

Wenn der angeforderte Schlüssel an keinem dieser Speicherorte gefunden wird, tritt ein XAML-Analysefehler/eine Ausnahme auf. Unter bestimmten Umständen kann es sich bei der XAML-Analyseausnahme um eine Laufzeitausnahme handeln, die weder durch eine XAML-Markupkompilierungsaktion noch durch eine XAML-Designumgebung erkannt wird.

Aufgrund des mehrstufigen Suchverhaltens für Ressourcenverzeichnisse können Sie absichtlich mehrere Ressourcenelemente definieren, die jeweils den gleichen Zeichenkettenwert wie der Schlüssel aufweisen, solange jede Ressource auf einer anderen Ebene definiert ist. Anders ausgedrückt: Auch wenn die Schlüssel in einem bestimmten ResourceDictionary eindeutig sein müssen, gilt die Anforderung an die Eindeutigkeit jedoch nicht für die gesamte Sequenz des Suchverhaltens. Bei der Suche wird nur das erste Objekt, das erfolgreich abgerufen wird, für den XAML-Ressourcenverweis verwendet, und dann wird die Suche beendet. Sie können dieses Verhalten verwenden, um dieselbe XAML-Ressource nach Schlüssel an verschiedenen Positionen im XAML-Code Ihrer App anzufordern, aber je nach Bereich, aus dem der XAML-Ressourcenverweis hergestellt wurde, und wie sich diese bestimmte Suche verhält, erhalten Sie unterschiedlichen Ressourcen.

Vorwärtsverweise in einem ResourceDictionary

XAML-Ressourcenverweise innerhalb eines bestimmten Ressourcenverzeichnisses müssen auf eine Ressource verweisen, die bereits mit einem Schlüssel definiert wurde, und diese Ressource muss lexikalisch vor dem Ressourcenverweis erscheinen. Vorwärtsverweise können nicht von einem XAML-Ressourcenverweis aufgelöst werden. Aus diesem Grund müssen Sie, wenn Sie XAML-Ressourcenverweise aus einer anderen Ressource verwenden, ihre Ressourcenverzeichnisstruktur so entwerfen, dass die Ressourcen, die von anderen Ressourcen verwendet werden, zuerst in einem Ressourcenverzeichnis definiert werden.

Ressourcen, die auf App-Ebene definiert sind, können keine Verweise auf unmittelbare Ressourcen erstellen. Dies entspricht dem Versuch eines Vorwärtsverweises, da die App-Ressourcen tatsächlich zuerst verarbeitet werden (beim ersten Start der App und vor dem Laden von Navigationsseiteninhalten). Jede unmittelbare Ressource kann jedoch einen Verweis auf eine App-Ressource erstellen, und dies kann eine nützliche Technik sein, um Vorwärtsverweissituationen zu vermeiden.

XAML-Ressourcen müssen freigabefähig sein

Damit ein Objekt in ResourceDictionary vorhanden sein kann, muss das Objekt freigabefähig sein.

Die Freigabefähigkeit ist erforderlich, da Objekte nicht an mehreren Stellen in der Struktur vorhanden sein können, wenn die Objektstruktur einer App zur Laufzeit erstellt und verwendet wird. Intern erstellt das Ressourcensystem Kopien von Ressourcenwerten, die im Objektgraph Ihrer App verwendet werden sollen, wenn jede XAML-Ressource angefordert wird.

Ein ResourceDictionary und Windows-Runtime-XAML unterstützen die folgenden Objekte in der Regel für die freigabefähige Verwendung:

Sie können auch benutzerdefinierte Typen als freigabefähige Ressource verwenden, wenn Sie den erforderlichen Implementierungsmustern folgen. Sie definieren solche Klassen in Ihrem Sicherungscode (oder in von Ihnen eingeschlossenen Laufzeitkomponenten) und instanziieren diese Klassen dann in XAML als Ressource. Beispiele dafür sind Objektdatenquellen und IValueConverter-Implementierungen für die Datenbindung.

Benutzerdefinierte Typen müssen über einen Standardkonstruktor verfügen, da dieser von einem XAML-Parser zum Instanziieren einer Klasse verwendet wird. Benutzerdefinierte Typen, die als Ressourcen verwendet werden, können in ihrer Vererbung die UIElement-Klasse nicht besitzen, weil ein UIElement niemals freigabefähig sein kann (sie stellt immer genau ein UI-Element dar, das an einer Position im Objektgraphen Ihrer Laufzeit-App vorhanden ist).

UserControl-Verwendungsbereich

Ein UserControl-Element umfasst eine spezielle Situation für das Ressourcensuchverhalten, da es die vererbten Konzepte eines Definitions- und Verwendungsbereichs enthält. Eine UserControl, die einen XAML-Ressourcenverweis aus seinem Definitionsbereich erstellt, muss in der Lage sein, die Suche dieser Ressource innerhalb der eigenen Definitionsbereich-Suchsequenz zu unterstützen, d. h. die kann nicht auf App-Ressourcen zugreifen. Aus einem UserControl-Verwendungsbereich wird ein Ressourcenverweis so behandelt, dass er sich in der Suchsequenz hin zum Verwendungsseitenstamm befindet (genau wie jeder andere aus einem Objekt in einer geladenen Objektstruktur erstellte Ressourcenverweis) und kann auf App-Ressourcen zugreifen.

ResourceDictionary und XamlReader.Load

Sie können ein ResourceDictionary als Stamm oder als Teil der XAML-Eingabe für die XamlReader.Load-Methode verwenden. Sie können auch XAML-Ressourcenverweise in diesen XAML-Code einschließen, wenn alle derartigen Verweise komplett eigenständig in dem XAML-Code enthalten sind, der zum Laden übermittelt wird. XamlReader.Load analysiert den XAML-Code in einem Kontext, in dem keine anderen ResourceDictionary-Objekte beachtet werden, nicht einmal Application.Resources. Verwenden Sie auch nicht {ThemeResource} innerhalb von XAML-Code, der an XamlReader.Load übermittelt wurde.

Verwenden eines ResourceDictionary aus Code

Die meisten Szenarien für ein ResourceDictionary werden ausschließlich im XAML-Code behandelt. Sie deklarieren den ResourceDictionary-Container und die darin befindlichen Ressourcen als XAML-Datei oder XAML-Knoten-Satz in einer Benutzeroberflächen-Definitionsdatei. Anschließend verwenden Sie XAML-Ressourcenverweise, um diese Ressourcen aus anderen Teilen des XAML-Codes anzufordern. Dennoch gibt es bestimmte Szenarien, in denen Ihre App den Inhalt eines ResourceDictionary mithilfe von Code anpassen möchte, der während der Ausführung der App ausgeführt wird, oder zumindest den Inhalt eines ResourceDictionary abzufragen möchte, um festzustellen, ob eine Ressource bereits definiert ist. Diese Codeaufrufe werden für eine ResourceDictionary-Instanz erstellt. Daher müssen Sie eine Instanz abrufen, und zwar entweder ein direktes ResourceDictionary in der Objektstruktur durch Abrufen von FrameworkElement.Resources oder Application.Current.Resources.

In C#- oder Microsoft Visual Basic-Code können Sie in einem bestimmten ResourceDictionary mithilfe des Indexers (Item) auf eine Ressource verweisen. Ein ResourceDictionary ist ein mit Zeichenkette versehenes Verzeichnis. Der Indexer verwendet also den Zeichenkettenschlüssel anstelle eines ganzzahligen Index. Für Visual C++-Komponentenerweiterungscode (C++/CX) verwenden Sie Lookup.

Bei der Verwendung von Code zum Untersuchen oder Ändern eines ResourceDictionary-Elements wechselt das Verhalten für APIs wie Lookup oder Item nicht von direkten Ressourcen zu App-Ressourcen. Dies ist das Verhalten eines XAML-Parsers, das nur beim Laden von XAML-Seiten auftritt. Zur Laufzeit ist der Bereich für Schlüssel in der ResourceDictionary-Instanz eigenständig, die Sie zu der Zeit verwenden. Der Bereich wird jedoch auf MergedDictionaries erweitert.

Wenn Sie zudem einen Schlüssel anfordern, der im ResourceDictionary nicht vorhanden ist, tritt ggf. kein Fehler auf. Für den Rückgabewert kann einfach NULL angegeben werden. Wenn Sie jedoch versuchen, das zurückgegebene null als Wert zu verwenden, wird möglicherweise trotzdem ein Fehler angezeigt. Der Fehler stammt aus dem Setter der Eigenschaft, nicht von Ihrem ResourceDictionary-Aufruf. Die einzige Möglichkeit, einen Fehler zu vermeiden, wäre, wenn die Eigenschaft null als gültigen Wert akzeptieren würde. Beachten Sie, wie sich dieses Verhalten mit dem XAML–Suchverhalten zur XAML-Analysezeit unterscheidet. Ein Fehler beim Beheben des bereitgestellten Schlüssels aus XAML zur Analysezeit führt zu einem XAML-Analysefehler, selbst in Fällen, in denen die Eigenschaft null akzeptiert haben könnte.

Zusammengeführte Ressourcenverzeichnisse sind im Indexbereich des primären Ressourcenverzeichnisses enthalten, der zur Laufzeit auf das zusammengeführte Verzeichnis verweist. Das heißt, dass Sie Item oder Lookup des primären Verzeichnisses zum Suchen von Objekten verwenden können, die tatsächlich im zusammengeführten Verzeichnis definiert wurden. In diesem Fall ähnelt das Suchverhalten dem Analysezeit-XAML-Suchverhalten: Wenn mehrere Objekte in zusammengeführten Verzeichnissen vorhanden sind, die jeweils denselben Schlüssel aufweisen, wird das Objekt aus dem zuletzt hinzugefügten Verzeichnis zurückgegeben.

Sie können einem vorhandenen ResourceDictionary Elemente hinzufügen, indem Sie Add (C# oder Visual Basic) oder Insert (C++/CX) aufrufen. Sie können die Elemente entweder unmittelbaren Ressourcen oder App-Ressourcen hinzufügen. Jeder dieser API-Aufrufe erfordert einen Schlüssel, der die Anforderung erfüllt, dass jedes Element in einem ResourceDictionary über einen Schlüssel verfügen muss. Elemente, die Sie einem ResourceDictionary zur Laufzeit hinzufügen, sind jedoch für XAML-Ressourcenverweise nicht relevant. Die erforderliche Suche für XAML-Ressourcenverweise erfolgt, wenn der XAML-Code zum ersten Mal analysiert wird, wenn die App geladen wird (oder eine Designänderung erkannt wird). Ressourcen, die Sammlungen zur Laufzeit hinzugefügt wurden, waren dann nicht verfügbar, und das Ändern des ResourceDictionary annulliert keine bereits abgerufene Ressource daraus, auch wenn Sie den Wert dieser Ressource ändern.

Sie haben auch die Möglichkeit, zur Laufzeit Elemente aus einem ResourceDictionary zu entfernen, Kopien von einigen oder allen Elementen zu erstellen und andere Vorgänge auszuführen. Die Mitgliederauflistung für ResourceDictionary gibt an, welche APIs verfügbar sind. Hinweis: Da das ResourceDictionary eine projizierte API zur Unterstützung der zugrunde liegenden Sammlungsschnittstellen aufweist, gilt es zu beachten, dass Ihre API-Optionen je nach Verwendung von C# oder Visual Basic anstelle von C++/CX variieren.

ResourceDictionary und Lokalisierung

Ein XAML-ResourceDictionary enthält anfangs unter Umständen Zeichenfolgen, die lokalisiert werden müssen. Wenn ja, speichern Sie diese Zeichenketten als Projektressourcen anstatt in einem ResourceDictionary. Nehmen Sie die Zeichenfolgen aus dem XAML-Code und weisen Sie stattdessen dem besitzenden Element einen x:Uid-Direktive-Wert zu. Definieren Sie dann eine Ressource in einer Ressourcendatei. Geben Sie einen Ressourcennamen im Format XUIDValue.PropertyName und einen Ressourcenwert der Zeichenkette an, die lokalisiert werden soll.

Benutzerdefinierte Ressourcensuche

Für erweiterte Szenarien können Sie eine Klasse implementieren, die ein anderes Verhalten aufweisen kann als das in diesem Thema beschriebene XAML-Ressourcenverweis-Suchverhalten. Implementieren Sie dazu die CustomXamlResourceLoader-Klasse. Sie können dann mit der CustomResource-Markuperweiterung statt über StaticResource oder ThemeResource auf dieses Verhalten zugreifen. Die meisten Apps verfügen nicht über Szenarien, die dies erfordern. Weitere Informationen finden Sie unter CustomXamlResourceLoader.