Übersicht über XAML-Ressourcen
Eine Ressource ist ein Objekt, das an verschiedenen Stellen in Ihrer App wiederverwendet werden kann. Beispiele für Ressourcen sind unter anderem Pinsel und Stile. In dieser Übersicht wird beschrieben, wie Ressourcen in Extensible Application Markup Language (XAML) verwendet werden. Sie können ressourcen auch mithilfe von Code erstellen und auf sie zugreifen.
Anmerkung
Die in diesem Artikel beschriebenen XAML-Ressourcen unterscheiden sich von App-Ressourcen, die in der Regel Dateien sind, die einer App hinzugefügt werden, z. B. Inhalte, Daten oder eingebettete Dateien.
Verwenden von Ressourcen in XAML
Im folgenden Beispiel wird eine SolidColorBrush als Ressource im Stammelement einer Seite definiert. Das Beispiel bezieht sich dann auf die Ressource und verwendet sie, um Eigenschaften mehrerer untergeordneter Elemente festzulegen, einschließlich eines Ellipse, eines TextBlockund eines Button.
<Page Name="root"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://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) verfügt über eine Resources-Eigenschaft, bei der es sich um einen ResourceDictionary Typ handelt, der definierte Ressourcen enthält. Sie können Ressourcen für jedes Element definieren, z. B. ein Button. Ressourcen werden jedoch am häufigsten für das Stammelement definiert, das im Beispiel Page ist.
Jede Ressource in einem Ressourcenverzeichnis muss über einen eindeutigen Schlüssel verfügen. Wenn Sie Ressourcen im Markup definieren, weisen Sie den eindeutigen Schlüssel über die x:Key Directivezu. In der Regel ist der Schlüssel eine Zeichenfolge; Sie können sie jedoch auch auf andere Objekttypen festlegen, indem Sie die entsprechenden Markuperweiterungen verwenden. Nicht-String-Schlüssel für Ressourcen werden in bestimmten Funktionsbereichen von WPF verwendet, insbesondere für Stile, Komponentenressourcen und Datenstile.
Sie können eine definierte Ressource mit der Syntax der Ressourcenmarkuperweiterung verwenden, die den Schlüsselnamen der Ressource angibt. Verwenden Sie beispielsweise die Ressource als Wert einer Eigenschaft für ein anderes Element.
<Button Background="{StaticResource MyBrush}"/>
<Ellipse Fill="{StaticResource MyBrush}"/>
Wenn das XAML-Ladeprogramm im vorherigen Beispiel den Wert {StaticResource MyBrush}
für die Background-Eigenschaft für Buttonverarbeitet, überprüft die Ressourcensuchlogik zunächst das Ressourcenwörterbuch für das Button-Element. Wenn Button keine Definition des Ressourcenschlüssels MyBrush
hat (in diesem Beispiel nicht; die Ressourcenauflistung ist leer), überprüft die Suche das übergeordnete Element von Button, das Pageist. Wenn Sie eine Ressource für das Page Stammelement definieren, können alle Elemente in der logischen Struktur der Page darauf zugreifen. Außerdem können Sie dieselbe Ressource wiederverwenden, um den Wert einer beliebigen Eigenschaft festzulegen, die denselben Typ akzeptiert, den die Ressource darstellt. Im vorherigen Beispiel wird mit derselben MyBrush
Ressource zwei verschiedene Eigenschaften festgelegt: die Background eines Buttonund die Fill eines Rectangle.
Statische und dynamische Ressourcen
Auf eine Ressource kann entweder als statisch oder dynamisch verwiesen werden. Verweise werden entweder mithilfe der StaticResource-Markuperweiterung oder der DynamicResource-Markuperweiterungerstellt. Eine Markup-Erweiterung ist ein XAML-Feature, mit dem Sie einen Objektverweis angeben können, indem die Attributzeichenfolge verarbeitet und das Objekt an einen XAML-Lader 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 Zeichenfolgenform bereit, die von dieser bestimmten Markuperweiterung verarbeitet werden. Die StaticResource-Markup-Erweiterung verarbeitet einen Schlüssel, indem der Wert für diesen Schlüssel in allen verfügbaren Ressourcenwörterbüchern nachgeschlagen wird. Die Verarbeitung erfolgt während des Ladens. Dies ist der Fall, wenn der Ladevorgang den Eigenschaftswert zuweisen muss. Die DynamicResource-Markuperweiterung verarbeitet stattdessen einen Schlüssel, indem ein Ausdruck erstellt wird, und dieser Ausdruck bleibt bis zur Ausführung der App nicht ausgewertet, zu diesem Zeitpunkt wird der Ausdruck ausgewertet und stellt einen Wert bereit.
Wenn Sie auf eine Ressource verweisen, können die folgenden Überlegungen beeinflussen, ob Sie einen statischen Ressourcenverweis oder einen dynamischen Ressourcenverweis verwenden:
Berücksichtigen Sie bei der Festlegung des Gesamtdesigns, wie Sie bei der Erstellung der Ressourcen für Ihre App vorgehen (pro Seite, in der App, in loses XAML oder in einer nur für Ressourcen vorgesehenen Assembly), folgende Überlegungen:
Die Funktionalität der App. Sind das Aktualisieren von Ressourcen in Echtzeit Teil Ihrer App-Anforderungen?
Das spezifische Abfrageverhalten dieses Ressourcenverweistyps.
Die jeweilige Eigenschaft oder der Ressourcentyp und das natürliche Verhalten dieser Typen.
Statische Ressourcen
Statische Ressourcenverweise funktionieren am besten für die folgenden Umstände:
Ihr App-Design konzentriert die meisten Ressourcen in Seiten- oder anwendungsbezogene Ressourcendiagramme. Statische Ressourcenverweise werden nicht basierend auf Laufzeitverhalten neu ausgewertet, z. B. das Neuladen einer Seite. Es kann also von Vorteil sein, eine große Anzahl dynamischer Ressourcenverweise zu vermeiden, wenn sie nach Ihrem Ressourcen- und App-Design nicht notwendig sind.
Sie legen den Wert einer Eigenschaft fest, die sich nicht auf einem DependencyObject oder einer Freezablebefindet.
Sie erstellen ein Ressourcenwörterbuch, das in eine DLL kompiliert und als Teil der App oder zwischen Apps freigegeben wird.
Sie erstellen ein Design für ein benutzerdefiniertes Steuerelement und definieren Ressourcen, die in den Designs verwendet werden. In diesem Fall ist das Verhalten des dynamischen Ressourcenverweises in der Regel unerwünscht; stattdessen möchten Sie das Verhalten des statischen Ressourcenverweises, um eine vorhersagbare und in sich geschlossene Suche innerhalb des Themas zu gewährleisten. Bei einem dynamischen Ressourcenverweis wird sogar ein Verweis innerhalb eines Designs bis zur Laufzeit nicht ausgewertet. und es besteht die Möglichkeit, dass beim Anwenden des Designs ein lokales Element einen Schlüssel neu definiert, auf den das Design verweist, und das lokale Element fällt vor dem Design selbst im Nachschlagevorgang. In diesem Fall verhält sich das Thema nicht wie erwartet.
Sie verwenden Ressourcen, um eine große Anzahl von Abhängigkeitseigenschaften festzulegen. Abhängigkeitseigenschaften verfügen über eine effektive Wertzwischenspeicherung, die durch das Eigenschaftensystem aktiviert wird. Wenn Sie also einen Wert für eine Abhängigkeitseigenschaft bereitstellen, der zur Ladezeit ausgewertet werden kann, muss die Abhängigkeitseigenschaft den Ausdruck nicht erneut auswerten und kann den letzten effektiven Wert zurückgeben. Diese Technik kann ein Leistungsvorteil sein.
Sie möchten die zugrunde liegende Ressource für alle Verbraucher ändern oder separate schreibbare Instanzen für jeden Verbraucher verwalten, indem Sie das x:Shared-Attributverwenden.
Verhalten der statischen Ressourcensuche
Der folgende Prozess beschreibt den Suchvorgang, der automatisch erfolgt, wenn eine statische Ressource durch eine Eigenschaft oder ein Element referenziert wird:
Der Nachschlagevorgang überprüft den angeforderten Schlüssel innerhalb des vom Element festgelegten Ressourcenwörterbuchs, das die Eigenschaft definiert.
Der Nachschlagevorgang durchläuft dann den logischen Baum nach oben zum übergeordneten Element und dessen Ressourcenverzeichnis. Dieser Vorgang wird fortgesetzt, bis das Stammelement erreicht ist.
App-Ressourcen werden überprüft. App-Ressourcen sind die Ressourcen im Ressourcenwörterbuch, die vom Application-Objekt für Ihre WPF-App definiert werden.
Statische Ressourcenverweise aus einem Ressourcenverzeichnis müssen auf eine Ressource verweisen, die bereits vor dem Ressourcenverweis lexikalisch definiert wurde. Vorwärtsverweise können nicht durch einen statischen Ressourcenverweis aufgelöst werden. Entwerfen Sie aus diesem Grund die Struktur Ihres Ressourcenwörterbuchs so, dass Ressourcen am oder nahe dem Anfang jedes Ressourcenwörterbuchs definiert sind.
Statische Ressourcensuche kann in Themen oder in Systemressourcen übergreifen, aber diese Unterstützung erfolgt nur, weil das XAML-Ladeprogramm die Anforderung verschiebt. Der Aufschub ist erforderlich, damit das Laufzeitdesign beim Laden der Seite richtig auf die App angewendet wird. Statische Ressourcenverweise auf Schlüssel, die nur in Themen oder als Systemressourcen vorhanden sind, werden nicht empfohlen, da solche Verweise nicht neu ausgewertet werden, wenn das Thema vom Benutzer in Echtzeit geändert wird. Ein dynamischer Ressourcenverweis ist zuverlässiger, wenn Sie Themen- oder Systemressourcen anfordern. Die Ausnahme ist, wenn ein Designelement selbst eine andere Ressource anfordert. Diese Verweise sollten statische Ressourcenverweise sein, aus den oben genannten Gründen.
Das Ausnahmeverhalten, wenn ein statischer Ressourcenverweis nicht gefunden wird, variiert. Wenn die Ressource zurückgestellt wurde, tritt die Ausnahme während der Laufzeit auf. Wenn die Ressource nicht zurückgestellt wurde, tritt die Ausnahme zum Ladezeitpunkt auf.
Dynamische Ressourcen
Dynamische Ressourcen funktionieren am besten, wenn:
Der Wert der Ressource, einschließlich der Systemressourcen und derjenigen, die vom Benutzer konfiguriert werden können, hängt von Bedingungen ab, die erst zur Laufzeit bekannt werden. Sie können z. B. Setterwerte erstellen, die auf Systemeigenschaften verweisen, die durch SystemColors, SystemFontsoder SystemParametersverfügbar gemacht werden. Diese Werte sind wirklich dynamisch, da sie letztendlich aus der Laufzeitumgebung des Benutzers und Betriebssystems stammen. Möglicherweise haben Sie auch Anwendungsthemen, die sich ändern können, wobei der Ressourcenzugriff auf Seitenebene ebenfalls die Änderung erfassen muss.
Sie erstellen oder verweisen auf Themenstile für ein benutzerdefiniertes Steuerelement.
Sie möchten den Inhalt einer ResourceDictionary während des Lebenszyklus einer App anpassen.
Sie verfügen über eine komplizierte Ressourcenstruktur mit Abhängigkeiten, bei denen möglicherweise ein Vorwärtsverweis erforderlich ist. Statische Ressourcenverweise unterstützen keine Vorwärtsverweise, aber dynamische Ressourcenverweise tun dies, weil die Ressource erst zur Laufzeit ausgewertet werden muss, und Vorwärtsverweise daher kein relevantes Konzept sind.
Sie verweisen auf eine Ressource, die aus der Sicht eines Kompilierungs- oder Arbeitssatzes als groß angesehen wird, und diese Ressource wird möglicherweise nicht sofort verwendet, wenn die Seite geladen wird. Statische Ressourcenverweise werden immer aus XAML geladen, wenn die Seite geladen wird. Ein dynamischer Ressourcenverweis wird jedoch erst geladen, wenn er verwendet wird.
Sie erstellen eine Formatvorlage, in der Setterwerte möglicherweise aus anderen Werten stammen, die von Designs oder anderen Benutzereinstellungen beeinflusst werden.
Sie wenden Ressourcen auf Elemente an, die während der App-Lebensdauer möglicherweise in der logischen Struktur analysiert werden. Wenn Sie das übergeordnete Element auch ändern, ändert sich möglicherweise auch der Ressourcensuchbereich. Wenn Sie also möchten, dass die Ressource für ein neu analysiertes Element basierend auf dem neuen Bereich neu ausgewertet werden soll, verwenden Sie immer einen dynamischen Ressourcenverweis.
Dynamisches Ressourcen-Sucheverhalten
Das Suchverhalten für einen dynamischen Ressourcenverweis entspricht dem Nachschlageverhalten in Ihrem Code, wenn Sie FindResource oder SetResourceReferenceaufrufen.
Die Nachschlageprüfung überprüft den angeforderten Schlüssel innerhalb des Ressourcenwörterbuchs, das durch das Element definiert wird, das die Eigenschaft festlegt:
Wenn das Element eine Style-Eigenschaft definiert, wird das Resources-Wörterbuch der System.Windows.FrameworkElement.Style des Elements überprüft.
Wenn das Element eine Template-Eigenschaft definiert, wird das System.Windows.FrameworkTemplate.Resources-Wörterbuch des Elements überprüft.
Die Suche durchläuft die logische Struktur nach oben zum übergeordneten Element und dem zugehörigen Ressourcenwörterbuch. Dieser Vorgang wird fortgesetzt, bis das Stammelement erreicht ist.
App-Ressourcen werden überprüft. App-Ressourcen sind die Ressourcen innerhalb des Ressourcenwörterbuchs, die vom Application-Objekt für Ihre WPF-App definiert werden.
Das Designressourcenverzeichnis wird auf das derzeit aktive Design überprüft. Wenn sich das Design zur Laufzeit ändert, wird der Wert neu ausgewertet.
Systemressourcen werden überprüft.
Das Ausnahmeverhalten (falls vorhanden) kann variieren.
Wenn eine Ressource von einem FindResource-Aufruf angefordert und nicht gefunden wurde, wird eine Ausnahme ausgelöst.
Wenn eine Ressource durch einen TryFindResource Aufruf angefordert und nicht gefunden wird, wird keine Ausnahme ausgelöst, und der zurückgegebene Wert ist
null
. Wenn die festgelegte Eigenschaftnull
nicht akzeptiert, ist es dennoch möglich, dass je nach festgelegter Eigenschaft eine tiefere Ausnahme ausgelöst wird.Wenn eine Ressource von einem dynamischen Ressourcenverweis in XAML angefordert wurde und nicht gefunden wurde, hängt das Verhalten vom allgemeinen Eigenschaftensystem ab. Das allgemeine Verhalten ist so, als ob kein Eigenschaftseinstellungsvorgang auf der Ebene aufgetreten ist, auf der die Ressource vorhanden ist. Wenn Sie z. B. versuchen, den Hintergrund für ein einzelnes Schaltflächenelement mithilfe einer Ressource festzulegen, die nicht ausgewertet werden konnte, dann können keine Wertesatzergebnisse erzielt werden, der effektive Wert kann jedoch weiterhin von anderen Teilnehmern im Eigenschaftensystem und der Wertrangfolge stammen. Beispielsweise kann der Hintergrundwert immer noch aus einem lokal definierten Schaltflächenformat oder aus der Designformatvorlage stammen. Bei Eigenschaften, die nicht durch Designstile definiert sind, kann der effektive Wert nach einer fehlgeschlagenen Ressourcenauswertung aus dem Standardwert in den Eigenschaftenmetadaten stammen.
Einschränkungen
Dynamische Ressourcenverweise weisen einige wichtige Einschränkungen auf. Mindestens eine der folgenden Bedingungen muss erfüllt sein:
Die festgelegte Eigenschaft muss eine Eigenschaft für ein FrameworkElement oder FrameworkContentElementsein. Diese Eigenschaft muss durch eine DependencyPropertyabgesichert werden.
Der Bezug bezieht sich auf einen Wert innerhalb eines
StyleSetter
.Die festgelegte Eigenschaft muss eine Eigenschaft eines Freezable sein, die entweder als Wert einer FrameworkElement- oder FrameworkContentElement-Eigenschaft oder eines Setter-Werts bereitgestellt wird.
Da die festgelegte Eigenschaft eine DependencyProperty oder Freezable Eigenschaft sein muss, können die meisten Eigenschaftsänderungen an die Benutzeroberfläche weitergegeben werden, da eine Eigenschaftsänderung (der geänderte dynamische Ressourcenwert) vom Eigenschaftensystem bestätigt wird. Die meisten Steuerelemente enthalten Logik, die ein anderes Layout eines Steuerelements erzwingt, wenn sich ein DependencyProperty ändert und diese Eigenschaft sich auf das Layout auswirken kann. Nicht alle Eigenschaften, die eine DynamicResource-Markuperweiterung als ihren Wert haben, garantieren Echtzeitaktualisierungen in der Benutzeroberfläche. Diese Funktionalität kann je nach Eigenschaft, dem Typ, der die Eigenschaft besitzt, oder sogar der logischen Struktur Ihrer App variieren.
Stile, DataTemplates und implizite Schlüssel
Obwohl alle Elemente in einem ResourceDictionary über einen Schlüssel verfügen müssen, bedeutet dies nicht, dass alle Ressourcen über eine explizite x:Key
verfügen müssen. Mehrere Objekttypen unterstützen einen impliziten Schlüssel, wenn er als Ressource definiert ist, wobei der Schlüsselwert an den Wert einer anderen Eigenschaft gebunden ist. Dieser Schlüsseltyp wird als impliziter Schlüssel bezeichnet, während ein x:Key
-Attribut ein expliziter Schlüssel ist. Sie können jeden impliziten Schlüssel überschreiben, indem Sie einen expliziten Schlüssel angeben.
Ein wichtiges Szenario für Ressourcen ist die Definition einer Style. Tatsächlich wird ein Style fast immer als Eintrag in einem Ressourcenwörterbuch definiert, da Formatvorlagen inhärent für die Wiederverwendung vorgesehen sind. Weitere Informationen zu Stilen finden Sie unter Styling und Templating.
Formatvorlagen für Steuerelemente können sowohl erstellt als auch referenziert werden, und zwar mit einem impliziten Schlüssel. Die Designstile, die die Standarddarstellung eines Steuerelements definieren, basieren auf diesem impliziten Schlüssel. Aus der Perspektive der Anforderung ist der implizite Schlüssel die Type des Steuerelements selbst. Aus der Sicht der Definition der Ressourcen ist der implizite Schlüssel die TargetType der Formatvorlage. Wenn Sie designs für benutzerdefinierte Steuerelemente erstellen oder Formatvorlagen erstellen, die mit vorhandenen Designformatvorlagen interagieren, müssen Sie daher keine x:Key-Direktive für dieses Styleangeben. Und wenn Sie die Designformatvorlagen verwenden möchten, müssen Sie überhaupt keine Formatvorlage angeben. Die folgende Stildefinition funktioniert beispielsweise, obwohl die Ressource Style anscheinend keinen Schlüssel hat.
<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 hat wirklich einen Schlüssel: der implizite Schlüssel typeof(System.Windows.Controls.Button)
. Im Markup können Sie eine TargetType direkt als Typnamen angeben (oder Sie können optional {x:Type...} verwenden, um eine Typezurückzugeben).
Über die von WPF verwendeten Standard-Stilmechanismen wird dieser Stil als Laufzeitstil einer Button auf der Seite angewendet, obwohl die Button selbst nicht versucht, ihre Style-Eigenschaft oder einen bestimmten Ressourcenverweis auf den Stil anzugeben. Ihre auf der Seite definierte Formatvorlage befindet sich weiter oben in der Nachschlagesequenz als der Designwörterbuchstil, wobei derselbe Schlüssel verwendet wird, den der Designwörterbuchstil aufweist. Sie können einfach <Button>Hello</Button>
irgendwo auf der Seite angeben, und die Formatvorlage, die Sie mit TargetType von Button
definiert haben, wird auf diese Schaltfläche angewendet. Um für Klarheit in Ihrem Markup zu sorgen, können Sie die Formatvorlage, wenn Sie möchten, weiterhin explizit mit demselben Typwert wie TargetType angeben, dies ist jedoch optional.
Implizite Schlüssel für Formatvorlagen gelten nicht für ein Steuerelement, wenn OverridesDefaultStyle gleich true
ist. (Beachten Sie außerdem, dass OverridesDefaultStyle als Teil des systemeigenen Verhaltens für die Steuerelementklasse festgelegt werden kann, anstatt explizit für eine Instanz des Steuerelements.) Um implizite Schlüssel für abgeleitete Klassenszenarien zu unterstützen, muss das Steuerelement DefaultStyleKey außer Kraft setzen (alle vorhandenen Steuerelemente, die als Teil von WPF bereitgestellt werden, umfassen diese Außerkraftsetzung). Weitere Informationen zu Stilen, Themen und Steuerelementdesigns finden Sie unter Richtlinien für das Entwerfen von anpassbaren Steuerelementen.
DataTemplate hat auch einen impliziten Schlüssel. Der implizite Schlüssel für eine DataTemplate ist der Eigenschaftswert von DataType. DataType kann auch als Name des Typs angegeben werden, anstatt explizit {x:Type...}zu verwenden. Ausführliche Informationen finden Sie in der Datentemplating-Übersicht.
Siehe auch
.NET Desktop feedback