This article has been localized into German by the community.
Ressourcen
WPF führt ein einfaches Konzept der Ressourcen ein: Daten in Ressourcen zu packen, egal ob lokal für ein Steuerelement, für das ganze Fenster oder global für die gesamte Anwendung. Die Daten können so gut wie alles sein, von aktuellen Informationen, bis hin zu der Hierarchie von WPF-Steuerelementen. Dies erlaubt es dir, Daten an einem Ort zu speichern und von anderen Orten aufzurufen. Dies ist sehr hilfreich in der Organisation.
Dieses Konzept nutzt überwiegend Stile (styles) und Entwurfsvorlagen (templates), welche wir später in diesem Tutorial erklären werden. Doch wie es in diesem Kapitel gezeigt wird, kannst du es in vielen anderen Bereichen auch nutzen. Hier ein einfaches Beispiel:
<Window x:Class="WpfTutorialSamples.WPF_Application.ResourceSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="ResourceSample" Height="150" Width="350">
<Window.Resources>
<sys:String x:Key="strHelloWorld">Hello, world!</sys:String>
</Window.Resources>
<StackPanel Margin="10">
<TextBlock Text="{StaticResource strHelloWorld}" FontSize="56" />
<TextBlock>Just another "<TextBlock Text="{StaticResource strHelloWorld}" />" example, but with resources!</TextBlock>
</StackPanel>
</Window>
Ressourcen erhalten einen Schlüssel, indem Sie das "x:Key-Attribut" verwenden. In Kombination des Schlüssels und der Markup-Erweiterung "StaticResource" (dt. StatischeRessource) wird ermöglicht, in anderen Teilen der Anwendung auf die Ressource zu verweisen. In diesem Beispiel speichere ich eine einfache Zeichenfolge, die ich dann für zwei verschiedenen Steuerelemente (hier TextBlock ) verwende.
Unterschied zwischen statischen und dynamischen Ressourcen
In den bisherigen Beispielen habe ich die Markup-Erweiterung "StaticResource" (dt. StatischeRessource) verwendet, um auf eine Ressource zu verweisen. Es existiert jedoch eine Alternative in Form der "DynamicResource" (dt. DynamischeRessource.)
Der Hauptunterschied besteht darin, dass eine statische Ressource nur einmal aufgelöst wird, und zwar an dem Punkt, an dem der XAML-Code geladen wird. Wenn die Ressource später geändert wird, werden die Änderung nicht dort angezeigt, wo Sie die statische Ressource verwendet haben.
Eine dynamische Ressource wird hingegen dann aufgelöst, sobald sie tatsächlich benötigt wird und erneut, wenn die Ressource sich ändert. Man kann es sich vorstellen wie bei einer Bindung an einen statischen Wert im Vergleich zu einer Bindung an eine Funktion, die einen Wert überwacht und diesen übermittelt sobald er sich ändert. Dies ist zwar nicht die exakte Funktionsweise aber es sollte Ihnen eine bessere Vorstellung davon geben, wann man welche verwenden sollte. Mit dynamischen Ressourcen kann man Ressourcen verwenden, die zur Zeit des Entwurfs der Methode noch nicht existiert haben, zum Beispiel beim späteren Hinzufügen beim Startup der Anwendung durch den Code-behind
Mehr Ressourcetypen
Das Teilen einer einfachen Zeichenfolge war einfach, aber Sie können noch viel mehr tun. Im nächsten Beispiel speichere ich ein komplettes Array (dt. Reihe oder Feld) von Strings (dt. Zeichenkette) zusammen mit einem Farbverlauf-Pinsel, der für den Hintergrund verwendet wird. Dies sollte Ihnen eine ziemlich gute Vorstellung davon geben, wie viel Sie mit Ressourcen machen können:
<Window x:Class="WpfTutorialSamples.WPF_Application.ExtendedResourceSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="ExtendedResourceSample" Height="160" Width="300"
Background="{DynamicResource WindowBackgroundBrush}">
<Window.Resources>
<sys:String x:Key="ComboBoxTitle">Items:</sys:String>
<x:Array x:Key="ComboBoxItems" Type="sys:String">
<sys:String>Item #1</sys:String>
<sys:String>Item #2</sys:String>
<sys:String>Item #3</sys:String>
</x:Array>
<LinearGradientBrush x:Key="WindowBackgroundBrush">
<GradientStop Offset="0" Color="Silver"/>
<GradientStop Offset="1" Color="Gray"/>
</LinearGradientBrush>
</Window.Resources>
<StackPanel Margin="10">
<Label Content="{StaticResource ComboBoxTitle}" />
<ComboBox ItemsSource="{StaticResource ComboBoxItems}" />
</StackPanel>
</Window>
Dieses Mal haben wir ein paar zusätzliche Ressourcen hinzugefügt, sodass unser Fenster jetzt einen einfachen String , ein Array von Strings und einen LinearGradientBrush (dt. Farbverlaufspinsel) enthält. Der String wird für das Label (dt. Etikette) verwendet, das Array von Strings wird als Element für das ComboBox-Steuerelement (dt. Kombinationsfeld) verwendet, und der Farbverlaufspinsel wird als Hintergrund für das gesamte Fenster-Objekt verwendet. Wie Sie sehen können, kann so ziemlich alles als Ressource gespeichert werden.
Lokale- und Anwendungsressourcen
Vorläufig haben wir Ressourcen auf der Fensterebene gespeichert, was bedeutet, dass Sie von überall im Fenster darauf zugreifen können.
Wenn Sie eine bestimmte Ressource für ein bestimmtes Steuerelement benötigen, können Sie sie lokal machen, indem Sie sie anstelle des Fensters zu dem spezifischen Steuerelement hinzufügen. Es klappt genauso, mit dem einzigen Unterschied, dass Sie nur innerhalb des Bereichs des Steuerelements aus zugreifen können, in dem Sie es so einfügen:
<StackPanel Margin="10">
<StackPanel.Resources>
<sys:String x:Key="ComboBoxTitle">Items:</sys:String>
</StackPanel.Resources>
<Label Content="{StaticResource ComboBoxTitle}" />
</StackPanel>
In diesem Fall fügen wir die Ressource zum StackPanel (dt. Stapelfeld) hinzu und verwenden sie dann von ihrem untergeordneten Steuerelement, dem Label. Andere Steuerelemente innerhalb des StackPanels können es ebenfalls verwenden, sowie die Kinder dieser untergeordneten Steuerelemente. Steuerelemente außerhalb dieses bestimmten StackPanels haben jedoch keinen Zugriff darauf.
Wenn Sie aus mehreren Fenstern auf die Ressource zugreifen möchten, ist dies ebenfalls möglich. Die App.xaml-Datei kann Ressourcen wie das Fenster und jede Art von WPF-Steuerelement enthalten. Wenn Sie sie in App.xaml speichern, sind sie global in allen Fenstern und Benutzersteuerelementen des Projekts verfügbar. Es funktioniert genauso wie beim speichern und verwenden aus einem Fenster:
<Application x:Class="WpfTutorialSamples.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
StartupUri="WPF application/ExtendedResourceSample.xaml">
<Application.Resources>
<sys:String x:Key="ComboBoxTitle">Items:</sys:String>
</Application.Resources>
</Application>
Es ist auch dasselbe - WPF wird automatisch den Bereich vom lokalen Steuerelement, zum Fenster und dann zur App.xaml hinaufgehen, um eine bestimmte Ressource zu finden:
<Label Content="{StaticResource ComboBoxTitle}" />
Ressourcen vom Hintergrundcode
Bis jetzt haben wir alle unsere Ressourcen direkt vom XAML-Code über eine Markup-Erweiterung aufgerufen. Sie können natürlich auch vom Hintergrundcode auf Ihre Ressourcen zugreifen, was in verschiedenen Situationen nützlich sein kann. Im vorherigen Beispiel haben wir gesehen, wie die Ressourcen an verschiedenen Stellen gespeichert werden können. In diesem Beispiel greifen wir auf drei verschiedene Ressourcen vom Hintergrundcode aus zu, die jeweils in verschiedenen Bereichen gespeichert sind:
App.xaml:
<Application x:Class="WpfTutorialSamples.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
StartupUri="WPF application/ResourcesFromCodeBehindSample.xaml">
<Application.Resources>
<sys:String x:Key="strApp">Hello, Application world!</sys:String>
</Application.Resources>
</Application>
Fenster:
<Window x:Class="WpfTutorialSamples.WPF_Application.ResourcesFromCodeBehindSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="ResourcesFromCodeBehindSample" Height="175" Width="250">
<Window.Resources>
<sys:String x:Key="strWindow">Hello, Window world!</sys:String>
</Window.Resources>
<DockPanel Margin="10" Name="pnlMain">
<DockPanel.Resources>
<sys:String x:Key="strPanel">Hello, Panel world!</sys:String>
</DockPanel.Resources>
<WrapPanel DockPanel.Dock="Top" HorizontalAlignment="Center" Margin="10">
<Button Name="btnClickMe" Click="btnClickMe_Click">Click me!</Button>
</WrapPanel>
<ListBox Name="lbResult" />
</DockPanel>
</Window>
Hintergrundcode:
using System;
using System.Windows;
namespace WpfTutorialSamples.WPF_Application
{
public partial class ResourcesFromCodeBehindSample : Window
{
public ResourcesFromCodeBehindSample()
{
InitializeComponent();
}
private void btnClickMe_Click(object sender, RoutedEventArgs e)
{
lbResult.Items.Add(pnlMain.FindResource("strPanel").ToString());
lbResult.Items.Add(this.FindResource("strWindow").ToString());
lbResult.Items.Add(Application.Current.FindResource("strApp").ToString());
}
}
}
Wie Sie sehen können, speichern wir drei verschiedene "Hallo, Welt!" Nachrichten: Eine in App.xaml, eine im Fenster und eine lokal für das Hauptfeld. Die Schnittstelle besteht aus einer Schaltfläche und einer ListBox (dt. Listenfeld).
Im Code-Behind behandeln wir das Klick-Event des Buttons, in welchem wir jeden String-Text zur ListBox hinzufügen, wie man im Screenshot sieht. Wir benutzen die FindResource()-Methode, welche die Ressource als object zurückgibt (falls gefunden), und dann konvertieren wir es im Wissen, dass es einen string ist, mit der ToString()-Methode.
Achte darauf, wie wir die FindResource()-Methode in verschiedenen Bereichen gebrauchen - zuerst auf demPanel, dann auf dem Window und dann auf dem aktuellen Application-Objekt. Es macht Sinn, dort nach der Ressource zu suchen, wo wir wissen, dass sie sich befindet. Aber wie bereits erwähnt, wenn eine Ressource nicht gefunden wird, geht die Suche hierarchisch höher weiter, also könnten wir die FindResource()-Methode prinzipiell auf dem Panel in allen drei Fällen benutzen, weil wir zum Window- und später zum Application-Level vordringen würden, falls nichts gefunden wird.
Dasselbe gilt aber nicht andersherum - die Suche navigiert im Tree nicht runter, also kann man die Suche nach einer Ressource nicht auf dem Application-Level starten, wenn sie lokal für das Control oder das Window definiert wurde.