23.2 Anwendungsübergreifende Ressourcen
Egal ob Sie eine Ressource in einer App.xaml-Datei hinterlegen, im Window oder einer WPF-Komponente, die Ressource ist nur in der aktuellen Anwendung bekannt. Vielfach werden aber auch Ressourcen benötigt, die von mehreren Anwendungen genutzt werden sollen. Dahinter könnte die Idee stecken, der Software ein allgemeines, unternehmensspezifisches Layout zu geben, beispielsweise einen hübschen, in jedem Fenster einheitlich verwendeten Hintergrund. Logische Ressourcen lassen sich in eine oder mehrere Ressourcendateien auslagern. Ressourcendateien können von mehreren verschiedenen Anwendungen gleichberechtigt genutzt werden, der XAML-Code wird übersichtlicher, und die Anwendung weist eine bessere Strukturierung auf. Zudem können Ressourcendateien zur Laufzeit ganz nach Bedarf nachgeladen werden.
Eine separate Ressourcendatei fügen Sie einer WPF-Anwendung als sogenanntes Ressourcenwörterbuch hinzu. Dafür gibt es eine namensgleiche Vorlage, die Sie der Anwendung zuerst hinzufügen müssen (siehe Abbildung 23.1). Über das Kontextmenü Hinzufügen des Projekts können Sie die Vorlage auswählen.
Abbildung 23.1 Die Vorlage »Ressourcenwörterbuch«
Ein Ressourcenwörterbuch ist eine XAML-Datei. Die XAML-Grundstruktur eines Ressourcenwörterbuchs wird mit dem Wurzelelement ResourceDictionary beschrieben und sieht wie in Listing gezeigt aus.
<ResourceDictionary
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Ressourcen -->
</ResourceDictionary>
Listing 23.1 Grundstruktur eines Ressourcenwörterbuchs
Im neu hinzugefügten Ressourcenwörterbuch sind neben dem Wurzelelement ResourceDictionary alle erforderlichen Namespaces angegeben. Tragen Sie hier alle Ressourcen ein, die Sie anwendungsübergreifend zur Verfügung stellen wollen.
Wir wollen uns den Einsatz der Ressourcenwörterbücher und deren Nutzung sofort an einem konkreten Beispiel ansehen. Dazu wird einem WPF-Anwendungsprojekt (Name: ResourceDictionarySample) ein Ressourcenwörterbuch mit dem Dateinamen Backgrounds.xaml hinzugefügt, und darin werden zwei Ressourcen definiert, die jeweils einen Farbverlauf beschreiben.
// Beispiel: ..\Kapitel 23\ResourceDictionarySample
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<LinearGradientBrush x:Key="background1" StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0.0" Color="White" />
<GradientStop Offset="1.0" Color="#FF646464" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="background2" StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0.0" Color="#FFF3E7E7" />
<GradientStop Offset="1.0" Color="#FF615C5C" />
</LinearGradientBrush>
</ResourceDictionary>
Listing 23.2 XAML-Code im Ressourcenwörterbuch
Beachten Sie bitte unbedingt, dass Ressourcen eindeutig benannt werden müssen. Hierzu dient das Attribut x:key, dem der Identifier als Zeichenfolge übergeben wird. Vergessen Sie die Angabe, erhalten Sie einen Compilerfehler.
Ressourcenwörterbücher müssen dem Programm bekannt gegeben werden. Benötigen Sie die in einem Ressourcenwörterbuch definierten Ressourcen nur in einem Window, reicht es aus, das Ressourcenwörterbuch im entsprechenden Fenster bekannt zu geben. Dazu eignet sich der Resource-Abschnitt des Window-Elements, z. B.:
<Window ... Background="{DynamicResource background1}">
<Window.Resources>
<ResourceDictionary Source="backgrounds.xaml" />
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Grid.Column="1" >
<Button Background="{StaticResource background2}" Margin="5">
Button 1
</Button>
<Button Background="{StaticResource background2}" Margin="5">
Button 2
</Button>
<Button Background="{StaticResource background2}" Margin="5">
Button 2
</Button>
</StackPanel>
</Grid>
</Window>
Listing 23.3 Der XAML-Code des Beispielprogramms »ResourceDictionarySample«
Auf die Beschreibung, wie ein Element auf eine Ressource zugreifen und sie nutzen kann, gehe ich an dieser Stelle noch nicht ein. Das wird ausführlich in Abschnitt 23.3 erörtert.
Wollen Sie die in einem Ressourcenwörterbuch zur Verfügung gestellten Ressourcen anwendungsweit nutzen, eignet sich dazu die Datei App.xaml. Geben Sie das Ressourcenwörterbuch einfach im Resources-Abschnitt an.
23.2.1 Mehrere Ressourcenwörterbücher
Logische Ressourcen lassen sich auch mehreren Ressourcenwörterbüchern entnehmen. Diese müssen dann im Abschnitt ResourceDictionary des Resources-Abschnitts mit der Eigenschaft MergedDictionarys zusammengeführt werden. Die Zusammenführung kann entweder lokal im Window oder in der Datei App.xaml erfolgen.
<Window x:Class="ExterneRessourcendatei.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Images.xaml" />
<ResourceDictionary Source="Backgrounds.xaml" />
[...]
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
<Window.Resources>
Listing 23.4 Mehrere Ressourcenwörterbücher im »Window« zusammenführen
Innerhalb eines Ressourcenwörterbuches müssen die Ressourcen eindeutig benannt werden. Leider lässt sich aber eine Doppeldeutigkeit nicht vermeiden. Dann wird nach der folgenden Regel verfahren: Sollten sich in mehreren Wörterbüchern gleichnamige Ressourcen befinden, wird letztendlich die Ressource abgerufen, die zuletzt genannt ist. Da bei mehreren Ressourcenwörterbüchern die Eindeutigkeit der Schlüssel nicht gewährleistet ist, sollten Sie das Ressourcenwörterbuch mit Vorrang zuletzt zur MergedDictionaries-Eigenschaft hinzufügen.
23.2.2 Die Suche nach einer Ressource
Bei so vielen unterschiedlichen Ebenen, in denen Ressourcen bereitgestellt werden können, stellt sich unweigerlich die Frage, nach welchem Muster die Suche nach einer Ressource abläuft. Im Grunde genommen ist der Ablauf sehr einfach.
Es lassen sich drei Bereiche angeben, in denen die Suche der Reihe nach durchgeführt wird:
- Die Suche beginnt im logischen Elementbaum. Hier wird zuerst die Resources-Eigenschaft des Elements geprüft, das die Suche initiiert hat. Anschließend wird der logische Elementbaum aufwärts untersucht. Dabei wird in jedem Element, das sich auf dem Pfad bis hin zum Wurzelelement befindet, nach dem entsprechenden Schlüssel gesucht.
- Wird im logischen Elementbaum der Schlüssel nicht gefunden, wird im Application-Objekt (entspricht dem Resource-Abschnitt in der Datei App.xaml) gesucht.
- Dem Application-Objekt sind noch die Systemressourcen übergeordnet. Zu den Systemressourcen werden die in den Klassen SystemColors, SystemParameters und SystemFonts vordefinierten Schlüssel gerechnet.
Wird die Ressource nicht gefunden, sind die Auswirkungen unterschiedlich, weil sie davon abhängen, wie die Ressource gebunden wird. Sie werden im folgenden Abschnitt erfahren, dass es die beiden Alternativen StaticResource und DynamicResource gibt. Es sei an dieser Stelle bereits erwähnt, dass die Suche nach einer statischen Ressource mit einer Ausnahme endet, wenn die Ressource nicht gefunden wird, während eine dynamische Ressource nicht zwangsläufig gefunden werden muss.
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.