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 einiger Objekte, die 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. Sie können Ihre Ressourcen mithilfe eines ResourceDictionary-Elements aus dem Windows-Runtime-XAML-Code definieren. Anschließend können Sie auf Ihre Ressourcen verweisen, indem Sie eine StaticResource-Markuperweiterung oder ThemeResource-Markuperweiterung verwenden.

Die XAML-Elemente, die Sie am häufigsten deklarieren möchten, da XAML-Ressourcen Stil, ControlTemplate, Animationskomponenten und Brush-Unterklassen enthalten. Hier erklären wir, wie Sie ein ResourceDictionary und Schlüsselressourcen definieren und wie XAML-Ressourcen sich auf andere Ressourcen beziehen, 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.

Hinweis

C# und C++/WinRT werden sowohl für WinUI 3/Windows App SDK- als auch für UWP-Apps unterstützt. C++/CX gilt nur für UWP und wird für WinUI 3 nicht unterstützt.

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

Verwechseln Sie die Konzepte im Zusammenhang mit ResourceDictionary nicht mit den Ressourcenbuildaktionen, Ressourcendateien (.resw) oder anderen "Ressourcen", die im Kontext der Strukturierung des Codeprojekts behandelt werden, das Ihr App-Paket erzeugt.

Ressourcen müssen keine Zeichenfolgen 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 einen mit x:Key="myString" definierten String. 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 Zeichenfolge. (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 Zeichenfolge.
  • x:Name kann an Stelle von x:Keyverwendet 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 jedoch auch nach impliziten Stilressourcen (die TargetType anstelle von x:Key oder x:Name verwenden), wenn es entscheidet, welche Formatvorlage für ein Steuerelement verwendet werden soll, das die Eigenschaften Style und ContentTemplate oder ItemTemplate nicht festgelegt hat.

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.

Ressourcen im Code nachschlagen

Sie greifen auf Mitglieder des Ressourcenwörterbuchs zu wie auf jedes andere Wörterbuch.

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.

  • Zuerst 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 Methode Application.OnLaunched hinzufügen.

// App.xaml.cs
    
sealed partial class App : Application
{
    protected override void OnLaunched(LaunchActivatedEventArgs e)
    {
        Frame rootFrame = m_window?.Content as Frame; // WinUI 3: Window.Current is always null; store the Window instance in a field
        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 = m_window.Content(); // WinUI 3: Window::Current() is always null; store the Window instance in a member field
    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)
    {
        Microsoft::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 ein Ressourcenverzeichnis haben.

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. Der TextBlock wird "Hola mundo" anzeigen.

Verwenden Sie die Resources-Eigenschaft dieses Elements, um über 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 Ressourcenverzeichnisse

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

Tipp Sie können eine Ressourcendatei in Microsoft Visual Studio erstellen, indem Sie im Menü Projekt die Option Neues Element hinzufügen … Ressourcenwörterbuch verwenden.

Hier definieren Sie ein Ressourcenwörterbuch in einer separaten XAML-Datei namens 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 Wörterbuch zu verwenden, führen Sie es mit dem Wörterbuch 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 übernimmt das Formular <ResourceDictionary Source="Dictionary1.xaml"/>. Wenn Sie mehr als ein Wörterbuch 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 Wörterbücher vorhanden sind, werden diese Wörterbücher in der umgekehrten Reihenfolge überprüft, 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 zuletzt im " MergedDictionaries "-Satz enthalten ist.

<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 Ressourcenwörterbuch.

Themenressourcen und Themenwörterbücher

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 Themenwörterbuch ist ein spezieller Typ zusammengeführter Wörterbücher, der die Ressourcen enthält, die je nach Thema variieren, das ein Nutzer 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 haben, aber unterschiedliche Werte.

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 Themenwörterbücher in den standardmäßigen XAML-Entwurfsressourcen strukturiert sind, die parallel zu den Vorlagen sind, die von der Windows-Runtime standardmäßig für dessen 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 Themenbereiche sind Duplikate dessen, was Sie in "generic.xaml" sehen würden.

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-Wörterbuchelementen, 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 Versuche der Ressourcensuche fehlschlagen, führt dies oft zu einem Fehler. 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 auf demselben 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 Nachschlagesequenz 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.

Von Bedeutung

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 umfassen 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 umfassen auch eine Reihe benannter Ressourcen, die sich auf das systemweite Erscheinungsbild und die Themen 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 designspezifischen und Systemressourcen, die für eine Windows-App verfügbar sind, 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-Parse-Ausnahme um einen Laufzeitfehler handeln, der weder durch eine XAML-Markupkompilierungsaktion noch durch eine XAML-Entwurfsumgebung erkannt wird.

Aufgrund des mehrstufigen Suchverhaltens für Ressourcenwörterbücher können Sie absichtlich mehrere Ressourcenelemente definieren, die jeweils den gleichen Zeichenfolgenwert 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 Ressourcenwörterbuchs müssen auf eine Ressource verweisen, die bereits mit einem Schlüssel definiert wurde, und diese Ressource muss lexikalisch vor dem Ressourcenverweis angezeigt werden. Vorwärtsreferenzen können nicht durch einen 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 Ressourcenwörterbuch definiert werden.

Ressourcen, die auf App-Ebene definiert sind, können keine Verweise auf sofortige Ressourcen erstellen. Dies entspricht dem Versuch eines Vorwärtsverweises, da die App-Ressourcen zuerst verarbeitet werden (beim ersten Start der App und vor dem Laden von Navigationsseiteninhalten). Jede sofortige 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 gemeinsam verwendet werden können

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 Objektdiagramm 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 gemeinsam nutzbare 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 sind Objektdatenquellen und Implementierungen von IValueConverter für die Datenbindung.

Benutzerdefinierte Typen müssen über einen Standardkonstruktor verfügen, da dies die Methode ist, die ein XAML-Parser verwendet, um eine Klasse zu instanziieren. 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, der keine anderen ResourceDictionary-Objekte kennt, 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 Ressourcen als XAML-Datei oder xaml-Knoten in einer UI-Definitionsdatei. Anschließend verwenden Sie XAML-Ressourcenverweise, um diese Ressourcen aus anderen Teilen von XAML 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 um den Inhalt eines ResourceDictionary abzufragen, 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# können Sie mithilfe des Indexers (Item) auf eine Ressource in einem bestimmten ResourceDictionary 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 auch einen Schlüssel anfordern, der im ResourceDictionary nicht vorhanden ist, tritt möglicherweise kein Fehler auf. Der Rückgabewert kann einfach als NULL angegeben werden. Wenn Sie jedoch versuchen, den zurückgegebenen null als Wert zu verwenden, kann dennoch ein Fehler auftreten. 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 Nachschlageverhalten dem Analysezeit-XAML-Nachschlageverhalten: Wenn mehrere Objekte in zusammengeführten Wörterbüchern vorhanden sind, die jeweils denselben Schlüssel aufweisen, wird das Objekt aus dem zuletzt hinzugefügten Wörterbuch zurückgegeben.

Sie dürfen einem vorhandenen ResourceDictionary Elemente hinzufügen, indem Sie Add oder Insert (C++/CX) aufrufen. Sie können die Elemente entweder unmittelbaren Ressourcen oder App-Ressourcen hinzufügen. Eine dieser API-Aufrufe erfordert einen Schlüssel, der die Anforderung erfüllt, dass jedes Element in einem ResourceDictionary über einen Schlüssel verfügt. 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 können auch Elemente aus einem ResourceDictionary- zur Laufzeit entfernen, Kopien einiger oder aller Elemente erstellen oder andere Vorgänge durchführen. Die Mitgliederauflistung für ResourceDictionary gibt an, welche APIs verfügbar sind. Da ResourceDictionary über eine projizierte API verfügt, um die zugrunde liegenden Sammlungsschnittstellen zu unterstützen, unterscheiden sich die API-Optionen je nachdem, ob Sie C# im Vergleich zu C++/CX verwenden.

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-Ressourcenreferenz-Nachschlageverhalten. Dazu implementieren Sie die Klasse CustomXamlResourceLoader, und dann können Sie mithilfe der CustomResource-Markuperweiterung für Ressourcenverweise auf dieses Verhalten zugreifen, anstatt StaticResource oder ThemeResourcezu verwenden. Die meisten Apps verfügen nicht über Szenarien, die dies erfordern. Weitere Informationen finden Sie unter CustomXamlResourceLoader.