Übersicht über Ressourcen
In dieser Übersicht wird erläutert, wie Sie mit WPF-Ressourcen auf einfache Weise häufig definierte Objekte und Werte wieder verwenden können. Diese Übersicht konzentriert sich auf die Verwendung von Ressourcen in XAML. Sie können Ressourcen auch mit Code oder im Wechsel zwischen Code und Extensible Application Markup Language (XAML) erstellen und darauf zugreifen. Weitere Informationen finden Sie unter Ressourcen und Code.
Dieses Thema enthält folgende Abschnitte.
- Verwenden von Ressourcen in XAML
- Statische und dynamische Ressourcen
- Stile, Datenvorlagen und implizite Schlüssel
- Verwandte Abschnitte
Verwenden von Ressourcen in XAML
Im folgenden Beispiel wird ein SolidColorBrush als Ressource für das Stammelement einer Seite definiert. Anschließend wird im Beispiel auf die Ressource verwiesen und diese zum Festlegen der Eigenschaften verschiedener untergeordneter Elemente verwendet, einschließlich Ellipse, TextBlock und Button.
<Page Name="root"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
>
<Page.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
<Style TargetType="Border" x:Key="PageBackground">
<Setter Property="Background" Value="Blue"/>
</Style>
<Style TargetType="TextBlock" x:Key="TitleText">
<Setter Property="Background" Value="Blue"/>
<Setter Property="DockPanel.Dock" Value="Top"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="Foreground" Value="#4E87D4"/>
<Setter Property="FontFamily" Value="Trebuchet MS"/>
<Setter Property="Margin" Value="0,40,10,10"/>
</Style>
<Style TargetType="TextBlock" x:Key="Label">
<Setter Property="DockPanel.Dock" Value="Right"/>
<Setter Property="FontSize" Value="8"/>
<Setter Property="Foreground" Value="{StaticResource MyBrush}"/>
<Setter Property="FontFamily" Value="Arial"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Margin" Value="0,3,10,0"/>
</Style>
</Page.Resources>
<StackPanel>
<Border Style="{StaticResource PageBackground}">
<DockPanel>
<TextBlock Style="{StaticResource TitleText}">Title</TextBlock>
<TextBlock Style="{StaticResource Label}">Label</TextBlock>
<TextBlock DockPanel.Dock="Top" HorizontalAlignment="Left" FontSize="36" Foreground="{StaticResource MyBrush}" Text="Text" Margin="20" />
<Button DockPanel.Dock="Top" HorizontalAlignment="Left" Height="30" Background="{StaticResource MyBrush}" Margin="40">Button</Button>
<Ellipse DockPanel.Dock="Top" HorizontalAlignment="Left" Width="100" Height="100" Fill="{StaticResource MyBrush}" Margin="40" />
</DockPanel>
</Border>
</StackPanel>
</Page>
Jedes Element auf Frameworkebene (FrameworkElement oder FrameworkContentElement) weist eine Resources-Eigenschaft auf, die die Ressourcen enthält (als ResourceDictionary), die von einer Ressource definiert werden. Sie können Ressourcen für jedes Element definieren. Ressourcen werden jedoch am häufigsten für das Stammelement definiert, das im Beispiel Page ist.
Jede Ressource in einem Ressourcenwörterbuch muss über einen eindeutigen Schlüssel verfügen. Wenn Sie Ressourcen in Markup definieren, weisen Sie den eindeutigen Schlüssel durch x:Key-Direktive zu. In der Regel handelt es sich beim Schlüssel um eine Zeichenfolge. Sie können ihn jedoch durch Verwenden der entsprechenden Markuperweiterungen auch auf andere Objekttypen festlegen. Schlüssel, die keine Zeichenfolge darstellen, werden in WPF in bestimmten Featurebereichen, besonders für Stile, Komponentenressourcen und Datenformatierung, verwendet.
Nach dem Definieren einer Ressource können Sie auf die Ressource verweisen, damit sie für einen Eigenschaftswert verwendet werden kann. Verwenden Sie dazu eine Markuperweiterungssyntax für Ressourcen, die den Schlüsselnamen angibt. Beispiel:
<Button Background="{StaticResource MyBrush}"/>
<Ellipse Fill="{StaticResource MyBrush}"/>
Wenn das XAML-Ladeprogramm im vorherigen Beispiel den {StaticResource MyBrush}-Wert für die Background-Eigenschaft für Button verarbeitet, prüft die Suchlogik der Ressource zunächst das Ressourcenwörterbuch auf das Button-Element. Wenn Button keine Definition des Ressourcenschlüssels MyBrush aufweist (es ist keine Definition vorhanden, die Ressourcenauflistung ist leer), prüft die Suchlogik als Nächstes das übergeordnete Element von Button, nämlich Page. Wenn Sie eine Ressource für das Page-Stammelement definieren, können daher alle Elemente in der logischen Struktur des Page-Elements darauf zugreifen. Sie können dieselbe Ressource zum Festlegen jeder Eigenschaft verwenden, die den Type akzeptiert, den die Ressource darstellt. Im vorherigen Beispiel legt dieselbe MyBrush-Ressource zwei verschiedene Eigenschaften fest: den Background eines Button-Elements und die Fill eines Rectangle-Elements.
Statische und dynamische Ressourcen
Auf eine Ressource kann entweder als statische Ressource oder als dynamische Ressource verwiesen werden. Hierzu wird entweder die StaticResource-Markuperweiterung oder die DynamicResource-Markuperweiterung verwendet. Eine Markuperweiterung ist ein Feature von XAML, mit dem Sie einen Objektverweis angeben können, indem die Markuperweiterung die Attributzeichenfolge verarbeitet und das Objekt an ein XAML-Ladeprogramm zurückgegeben wird. Weitere Informationen über das Verhalten von Markuperweiterungen finden Sie unter Markuperweiterungen und WPF-XAML.
Wenn Sie eine Markuperweiterung verwenden, stellen Sie in der Regel einen oder mehrere Parameter in Form einer Zeichenfolge bereit, die von dieser speziellen Markuperweiterung verarbeitet und nicht im Kontext der Eigenschaft, die festgelegt wird, ausgewertet werden. Die StaticResource-Markuperweiterung verarbeitet einen Schlüssel, indem der Wert für diesen Schlüssel in allen verfügbaren Ressourcenwörterbüchern gesucht wird. Dies geschieht beim Laden, dem Zeitpunkt, zu dem der Ladeprozess den Eigenschaftswert zuweisen muss, der den Verweis auf die statische Ressource akzeptiert. Die DynamicResource-Markuperweiterung verarbeitet einen Schlüssel dagegen durch Erstellen eines Ausdrucks, der nicht ausgewertet wird, bis die Anwendung tatsächlich ausgeführt wird. Zu diesem Zeitpunkt wird der Ausdruck ausgewertet und ein Wert zur Verfügung gestellt.
Wenn auf eine Ressource verwiesen wird, können die folgenden Überlegungen die Verwendung eines statischen bzw. eines dynamischen Ressourcenverweises beeinflussen:
Der allgemeine Entwurf zur Erstellung der Ressourcen für die Anwendung (pro Seite, in der Anwendung, in Loose XAML, in einer Assembly, die nur aus Ressourcen besteht).
Die Anwendungsfunktionalität: Ist die Aktualisierung der Ressourcen in Echtzeit Bestandteil der Anwendungsanforderungen?
Das jeweilige Suchverhalten der Ressourcenreferenztypen.
Die bestimmte Eigenschaft bzw. der bestimmte Ressourcentyp und das systemeigene Verhalten jener Typen.
Statische Ressourcen
Verweise auf statische Ressourcen sind am besten für folgende Umstände geeignet:
Der Anwendungsentwurf konzentriert sich vor allem auf die Ressourcen in Seiten oder auf Ressourcewörterbücher auf Anwendungsebene. Statische Ressourcen werden nicht auf Grundlage des Laufzeitverhaltens, wie dem erneuten Laden einer Seite, neu ausgewertet. Dadurch kann sich ein kleiner Leistungsvorteil ergeben, indem zu viele Verweise auf dynamische Ressourcen vermieden werden, sofern sie nicht für die Ressource und den Anwendungsentwurf erforderlich sind.
Sie legen den Wert einer Eigenschaft fest, die nicht für ein DependencyObject oder ein Freezable ist.
Sie erstellen ein Ressourcenwörterbuch, das in eine DLL kompiliert und als Teil der Anwendung gepackt oder von mehreren Anwendungen gemeinsam genutzt wird.
Sie erstellen ein Design für ein benutzerdefiniertes Steuerelement und definieren Ressourcen, die in den Designs verwendet werden. In diesem Fall ist das Suchverhalten des dynamischen Ressourcenverweises nicht erwünscht. Stattdessen möchten Sie das Verhalten des statischen Ressourcenverweises nutzen, damit die Suche vorhersagbar und auf das Design beschränkt ist. Bei einem dynamischen Ressourcenverweis wird selbst ein Verweis innerhalb des Designs erst zur Laufzeit ausgewertet. Außerdem besteht die Möglichkeit, dass beim Anwenden des Designs ein lokales Element einen Schlüssel, auf den das Design verweisen möchte, neu definiert und das lokale Element in der Suche vor das Design fällt. In diesem Fall verhält sich das Design nicht wie erwartet.
Sie verwenden Ressourcen, um eine größere Anzahl von Abhängigkeitseigenschaften festzulegen. Abhängigkeitseigenschaften weisen eine effektive Zwischenspeicherung von Werten auf, wie durch das Eigenschaftensystem aktiviert. Wenn Sie also einen Wert für eine Abhängigkeitseigenschaft bereitstellen, die zur Ladezeit ausgewertet werden kann, muss die Abhängigkeitseigenschaft nicht auf einen neu ausgewerteten Wert prüfen, sondern kann den letzten effektiven Wert zurückgeben. Diese Technik kann einen Leistungsvorteil bieten.
Sie möchten die zugrunde liegende Ressource für alle Consumer ändern oder separate Instanzen mit Schreibzugriff für jeden einzelnen Consumer mit dem x:Shared-Attribut verwalten.
Suchverhalten von statischen Ressourcen
Der Suchprozess prüft das Ressourcenwörterbuch, das von dem Element definiert wird, das die Eigenschaft festlegt, auf den angeforderten Schlüssel.
Der Suchprozess durchläuft dann die logische Struktur aufwärts zum übergeordneten Element und seinem Ressourcenwörterbuch. Dies wird fortgesetzt, bis das Stammelement erreicht wird.
Danach werden die Anwendungsressourcen geprüft. Bei Anwendungsressourcen handelt es sich um die Ressourcen in dem Ressourcenwörterbuch, das vom Application-Objekt für die WPF-Anwendung definiert wird.
Statische Ressourcenverweise aus einem Ressourcenwörterbuch müssen auf eine Ressource verweisen, die bereits vor dem Ressourcenverweis lexikalisch definiert wurde. Vorwärtsverweise können nicht von einem statischen Ressourcenverweis aufgelöst werden. Wenn Sie statische Ressourcenverweise verwenden, müssen Sie daher die Struktur des Ressourcenwörterbuchs so entwerfen, dass Ressourcen, die für die Verwendung durch eine Ressource vorgesehen sind, am Anfang oder in der Nähe des Anfangs des jeweiligen Ressourcenwörterbuchs definiert werden.
Die statische Ressourcensuche kann auf Designs oder die Systemressourcen ausgedehnt werden. Dies wird jedoch nur unterstützt, weil das XAML-Ladeprogramm die Anforderung zurückstellt. Die Zurückstellung ist erforderlich, damit das Laufzeitdesign beim Laden der Seite ordnungsgemäß auf die Anwendung angewendet werden kann. Jedoch sind statische Ressourcenverweise auf Schlüssel nur in Designs oder als Systemressourcen vorhanden und nicht empfehlenswert. Das liegt daran, dass diese Verweise nicht neu ausgewertet werden, wenn das Design in Echtzeit vom Benutzer geändert wird. Ein dynamischer Ressourcenverweis ist zuverlässiger, wenn Sie ein Design oder Systemressourcen anfordern. Eine Ausnahme besteht dann, wenn ein Designelement selbst eine andere Ressource anfordert. Für diese Verweise sollten aus den bereits genannten Gründen statische Ressourcenverweise verwendet werden.
Das Ausnahmeverhalten bei nicht gefundenem Ressourcenverweis ist variabel. Wenn die Ressource zurückgestellt wurde, tritt die Ausnahme zur Laufzeit auf. Wenn die Ressource nicht zurückgestellt wurde, tritt die Ausnahme bei Ladezeit auf.
Dynamische Ressourcen
Dynamische Ressourcen sind am besten für folgende Umstände geeignet:
Der Wert der Ressource hängt von Bedingungen ab, die erst zur Laufzeit bekannt werden. Dies schließt Systemressourcen oder Ressourcen ein, die andernfalls vom Benutzer festgelegt werden können. Beispielsweise könne Sie Setterwerte festlegen, die auf Systemeigenschaften verweisen, wie von SystemColors, SystemFonts oder SystemParameters verfügbar gemacht. Es handelt sich hierbei um echte dynamische Werte, da sie letztendlich aus der Laufzeitumgebung des Benutzers und dem Betriebssystem stammen. Möglicherweise verfügen Sie auch über Designs auf Anwendungsebene, die sich ändern können und bei denen der Ressourcenzugriff auf Seitenebene die Änderung ebenfalls erfassen muss.
Sie erstellen oder verweisen auf Designstile für ein benutzerdefiniertes Steuerelement.
Sie beabsichtigen, den Inhalt eines ResourceDictionary-Elements während der Lebensdauer einer Anwendung anzupassen.
Sie haben eine komplizierte Ressourcenstruktur mit gegenseitigen Abhängigkeiten, in der möglicherweise ein Vorwärtsverweis erforderlich wird. Statische Ressourcenverweise unterstützen keine Vorwärtsverweise. Dynamische Ressourcenverweise dagegen schon, weil die Ressource erst zur Laufzeit ausgewertet werden muss. Vorwärtsverweise sind daher nicht relevant.
Sie verweisen auf eine Ressource, die aus der Perspektive eines Compilesets oder Workingsets besonders groß ist. Außerdem wird die Ressource möglicherweise nicht unmittelbar beim Laden einer Seite verwendet. Statische Ressourcenverweise werden immer aus XAML geladen, wenn die Seite geladen wird. Ein dynamischer Ressourcenverweis wird dagegen erst geladen, wenn er tatsächlich verwendet wird.
Sie erstellen einen Stil, bei dem die Setterwerte von anderen Werten stammen können, die durch Designs oder andere Benutzereinstellungen beeinflusst werden.
Sie wenden Ressourcen auf Elemente an, denen während der Anwendungslebenszeit in der logischen Struktur übergeordnete Elemente neu zugeordnet werden. Das Ändern des übergeordneten Elements trägt zu einer potenziellen Änderung des Ressourcensuchbereichs bei. Wenn die Ressource für ein neu zugeordnetes Element auf Grundlage des neuen Bereichs neu ausgewertet werden soll, sollten Sie immer einen dynamischen Ressourcenverweis verwenden.
Suchverhalten von dynamischen Ressourcen
Das Ressourcensuchverhalten für einen dynamischen Verweis entspricht dem Suchverhalten im Code, wenn Sie FindResource oder SetResourceReference aufrufen.
Der Suchprozess prüft das Ressourcenwörterbuch, das von dem Element definiert wird, das die Eigenschaft festlegt, auf den angeforderten Schlüssel.
Der Suchprozess durchläuft dann die logische Struktur aufwärts zum übergeordneten Element und seinem Ressourcenwörterbuch. Dies wird fortgesetzt, bis das Stammelement erreicht wird.
Danach werden die Anwendungsressourcen geprüft. Bei Anwendungsressourcen handelt es sich um die Ressourcen in dem Ressourcenwörterbuch, das vom Application-Objekt für die WPF-Anwendung definiert wird.
Das Designressourcenwörterbuch für das gerade aktive Design wird geprüft. Wenn sich das Design zur Laufzeit ändert, wird der Wert neu ausgewertet.
Die Systemressourcen werden geprüft.
Das Ausnahmeverhalten (soweit vorhanden) variiert:
Wenn eine Ressource von einem FindResource-Aufruf angefordert und nicht gefunden wurde, wird eine Ausnahme ausgelöst.
Wenn eine Ressource von einem TryFindResource-Aufruf angefordert und nicht gefunden wurde, wird keine Ausnahme ausgelöst. Der zurückgegebene Wert ist jedoch null. Wenn die Eigenschaft, die festgelegt wird, null nicht akzeptiert, besteht die Möglichkeit, dass eine tiefere Ausnahme ausgelöst wird (das hängt von der jeweiligen Eigenschaft ab, die gerade festgelegt wird).
Wenn eine Ressource von einem dynamischen Ressourcenverweis in XAML angefordert und nicht gefunden wurde, hängt das Verhalten vom allgemeinen Eigenschaftensystem ab. Allgemein sieht das Verhalten so aus, als hätte kein Vorgang zum Festlegen einer Eigenschaft auf der Ebene stattgefunden, auf der sich die Ressource befindet. Wenn Sie z. B. versuchen, den Hintergrund für ein einzelnes Schaltflächenelement mit einer Ressource festzulegen, die nicht ausgewertet werden konnte, legt kein Wert das Ergebnis fest. Der effektive Wert kann jedoch immer noch von anderen Teilnehmern im Eigenschaftensystem kommen und Vorrang haben. Der Hintergrundwert kann beispielsweise immer noch von einem lokal definierten Schaltflächenstil oder vom Designstil kommen. Bei Eigenschaften, die nicht durch Designstile definiert sind, kann der effektive Wert nach einer fehlerhaften Ressourcenauswertung vom Standardwert in den Eigenschaftenmetadaten kommen.
Beschränkungen
Dynamische Ressourcenverweise haben einige wichtige Einschränkungen. Mindestens eine der folgen Aussagen muss zutreffen:
Die Eigenschaft, die festgelegt wird, muss eine Eigenschaft für ein FrameworkElement oder ein FrameworkContentElement sein. Diese Eigenschaft muss von einer DependencyProperty unterstützt werden.
Die Eigenschaft, die festgelegt wird, muss eine Eigenschaft für ein Freezable sein, das entweder als Wert der FrameworkElement-Eigenschaft oder der FrameworkContentElement-Eigenschaft oder als Setter-Wert zur Verfügung gestellt wird.
Weil die Eigenschaft, die festgelegt wird, eine DependencyProperty oder eine Freezable-Eigenschaft sein muss, können die meisten Eigenschaftenänderungen an die Benutzeroberfläche weitergegeben werden, weil eine Eigenschaftenänderung (der geänderte Wert der dynamischen Ressource) vom Eigenschaftensystem bestätigt wird. Die meisten Steuerelemente enthalten Logik, die ein anderes Layout eines Steuerelements erzwingt, wenn sich eine DependencyProperty ändert, und diese Eigenschaft sich auf das Layout auswirken könnte. Jedoch können nicht alle Eigenschaften mit einer DynamicResource-Markuperweiterung als Wert den Wert so bereitstellen, dass die Aktualisierungen in der Benutzeroberfläche in Echtzeit erfolgen. Die Funktionalität kann immer noch je nach Eigenschaft oder nach dem Typ, der die Eigenschaft besitzt, oder auch nach der logischen Struktur Ihrer Anwendung variieren.
Stile, Datenvorlagen und implizite Schlüssel
Es wurde bereits angemerkt, dass alle Elemente in einem ResourceDictionary über einen Schlüssel verfügen müssen. Das bedeutet jedoch nicht, dass alle Ressourcen einen expliziten x:Key haben müssen. Einige Objekttypen unterstützen einen impliziten Schlüssel, wenn dieser als Ressource definiert und der Schlüsselwert an den Wert einer anderen Eigenschaft gebunden ist. Dies wird als impliziter Schlüssel bezeichnet, während ein x:Key-Attribut ein expliziter Schlüssel ist. Sie können jeden impliziten Schlüssel durch Angabe eines expliziten Schlüssels überschreiben.
Ein sehr wichtiges Szenario für Ressourcen stellt das Definieren eines Style-Elements dar. Tatsächlich wird ein Style fast immer als Eintrag in einem Ressourcenwörterbuch definiert, weil Stile grundsätzlich zur Wiederverwendung vorgesehen sind. Weitere Informationen zu Stilen finden Sie unter Erstellen von Formaten und Vorlagen.
Stile für Steuerelemente können mit einem impliziten Schlüssel erstellt und es kann auch mit einem impliziten Schlüssel auf sie verwiesen werden. Die Designstile, die die Standarddarstellung eines Steuerelements definieren, sind auf diesen impliziten Schlüssel angewiesen. Aus Sicht der Anforderung handelt es sich beim impliziten Schlüssel um den Type des Steuerelements selbst. Aus Sicht der Ressourcendefinition handelt es sich beim impliziten Schlüssel um den TargetType des Stils. Wenn Sie Designs für benutzerdefinierte Steuerelemente oder Stile, die mit vorhandenen Designstilen interagieren, erstellen, müssen Sie daher kein x:Key-Direktive für diesen Style angeben. Und wenn Sie Designstile verwenden möchten, müssen Sie überhaupt keinen Stil angeben. Die folgende Stildefinition funktioniert beispielsweise, obwohl die Style-Ressource keinen Schlüssel zu haben scheint:
<Style TargetType="Button">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush>
<GradientStop Offset="0.0" Color="AliceBlue"/>
<GradientStop Offset="1.0" Color="Salmon"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="FontSize" Value="18"/>
</Style>
Dieser Stil verfügt tatsächlich über einen Schlüssel: den impliziten Schlüssel typeof(Button). In Markup können Sie einen TargetType direkt als Typnamen angeben (oder optional {x:Type...} verwenden, um einen Type zurückzugeben).
Durch die von WPF verwendeten Standardmechanismen für Designstile wird dieser Stil als Laufzeitstil eines Button-Elements auf der Seite angewendet, obwohl das Button-Element selbst nicht versucht, seine Style-Eigenschaft oder einen bestimmten Ressourcenverweis auf den Stil anzugeben. Der für die Seite definierte Stil wird in der Suchsequenz vor dem Designwörterbuchstil gefunden. Dabei wird derselbe Schlüssel wie der des Designwörterbuchstils verwendet. Geben Sie einfach irgendwo auf der Seite <Button>Hello</Button> an, und der mit dem TargetType von Button definierte Stil wird auf diese Schaltfläche angewendet. Wenn Sie möchten, können Sie dennoch einen expliziten Schlüssel für den Stil mit demselben Typwert wie TargetType angeben, damit Klarheit im Markup besteht. Dies ist jedoch optional.
Implizite Schlüssel für Stile können nicht auf ein Steuerelement angewendet werden, wenn OverridesDefaultStyle den Wert true hat (beachten Sie auch, dass OverridesDefaultStyle als Teil des systemeigenen Verhaltens für den Steuerelementtyp und nicht explizit für eine Instanz des Steuerelements festgelegt werden kann). Um implizite Schlüssel für abgeleitete Klassenszenarien zu unterstützen, muss das Steuerelement außerdem DefaultStyleKey überschreiben (alle vorhandenen Steuerelemente, die als Teil von WPF bereitgestellt werden, verhalten sich so). Weitere Informationen über Stile, Designs und Steuerelemententwürfe finden Sie unter Richtlinien zum Entwerfen formatierbarer Steuerelemente.
DataTemplate verfügt ebenfalls über einen impliziten Schlüssel. Der implizite Schlüssel für eine DataTemplate ist der DataType-Eigenschaftswert. DataType kann auch als Name des Typs angegeben werden, anstatt {x:Type...} explizit zu verwenden. Ausführliche Informationen finden Sie unter Übersicht über Datenvorlagen.
Siehe auch
Aufgaben
Gewusst wie: Definieren einer Ressource und Verweisen auf eine Ressource
Referenz
StaticResource-Markuperweiterung
DynamicResource-Markuperweiterung