This article has been localized into Danish by the community.
A special thanks goes out to user #1576 for the Danish translation of this article: Benny Tordrup
Ressourcer
WPF introducerer et meget anvendeligt concept: Evnen til at gemme data som en ressource - enten lokalt for en kontrol, lokalt for et vindue, eller globalt for hele applikationen. Data kan være stort set hvad, du ønsker fra egentlig information til et hierarki af WPF kontroller. Dette giver dig mulighed for at placere data et sted og derefter bruge det fra flere andre steder, hvilket er meget brugbart.
Konceptet benyttes meget for typografier og skabeloner, hvilket vi vil diskuttere senere i dette selvstudie, men som det vil blive illustreret i dette afsnit, kan du bruge det til mange andre ting også. Tillad mig at demonstrere med et simpelt eksempel:
<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>
Ressourcer gives en nøgle ved hjælp af x:Key attributten. Dette tillader dig at referere den fra andre dele af applikationen ved at bruge denne nøgle i forbindelse med StaticResource markup-udvidelsen. I dette eksempel gemmer jeg bare en simpel streng, som jeg derefter bruger fra to forskellige TextBlock kontroller
StaticResource vs. DynamicResource
I eksemplerne indtil nu har jeg brugt StaticResoure markup-udvidelsen til at referere en ressource. Men der findes et alternative i form af DynamicResource.
Den primære forskel er, at en statisk ressource kun fortolkes en gang, hvilket er på det tidspunkt XAML indlæses. Hvis ressourcen ændres efterfølgende, vil denne ændring ikke slå igennem der, hvor du bruger StaticResource.
En DynamicResource vil derimod blive fortolket, når den rent faktisk behøves, og derefter igen hvis ressourcen ændres. Tænk på det som en binding til en statisk værdi vs. binding til en function, som overvåger denne værdi og giver dig den nye værdi hver gang, den ændres. Det er ikke præcis sådan, det fungerer, men det bør give dig en bedre ide om hvornår, den skal bruges. Dynamiske ressourcer tillader dig også at bruge ressourcer, som ikke engang findes i design-tilstand, f.eks. hvis du tilføjer dem fra code-behind under start af applikationen.
Flere ressourcetyper
Deling af en simpel streng var nemt, men du kan gøre meget mere. I det næste eksempel vil jeg og gemme et komplet array af strenge sammen med en gradueringspensel til brug som baggrund. Dette skulle give dig en ide om hvor meget, du faktisk kan gøre med ressourcer.
<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>
Denne gang har vi tilføjet et par ekstra ressourcer således, at vores Window nu indeholder en simpel streng, et array af strenge og en LinearGradientBrush. Strengen bruges til etiketten, streng-arrayed bruges som elementer til ComboBox kontrollen, og gradueringspenslen bruges som baggrund til hele vinduet. Så, som du kan se, stort set hvad som helst kan gemmes som en ressource.
Lokale og applikationsglobale ressourcer
Indtil videre har vi gemt ressourcerne på Window-niveau, hvilket betyder, at du kan tilgå dem fra alle steder i vinduet.
Hvis du kun behøver en given ressource til en specific kontrol, kan du gøre den mere lokal ved at tilføje den til den specifikke kontrol i stedet for vinduet. Det virker på nøjagtig samme måde med den forskel, at du nu kun kan tilgå den inde i den kontrol, hvor du placerede den.
<StackPanel Margin="10">
<StackPanel.Resources>
<sys:String x:Key="ComboBoxTitle">Items:</sys:String>
</StackPanel.Resources>
<Label Content="{StaticResource ComboBoxTitle}" />
</StackPanel>
I dette tilfælde tilføjer vi ressourcen til StackPanel og bruger den derefter fra dens underordnede kontrol, Label kontrollen. Andre kontroller inde i StackPanel kunne også have brugt den, ganske som underordnede kontroller på disse underordnede kontroller vil være i stand til at tilgå den. Kontroller uden for dette specifikke StackPanel vil dog ikke have adgang til den.
Hvis du har brug for muligheden for at tilgå ressourcen fra flere vinduer, er dette også muligt. App.xaml filen kan indeholde ressourcer fuldstændig som vinduet og enhver WPF kontrol, og når du gemmer dem i App.xaml, er de tilgængelige i alle vinduer og brugerkontroller i projektet. Det virker på nøjagtig den samme måde som når de gemmes og bruges fra et Window:
<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>
Brug af den er også det samme - WPF vil automatisk gå op i område fra den locale kontrol til vinduet og derefter til App.xaml for at finde en given ressource:
<Label Content="{StaticResource ComboBoxTitle}" />
Ressourcer fra code-behind
Indtil videre har vi tilgået alle vores ressourcer Direkte fra XAML ved brug af en markup-udvidelse. Men du kan selvfølgelig også tilgå dine ressourcer fra code-behind, hvilket kan være brugbart i flere situationer. I det forrige eksempel så vi hvordan, vi kunne gemme ressourcer flere forskellige steder, så i dette eksempel vil vi tilgå tre forskellige ressourcer fra code-behind - hver af dem gemt i forskellige områder:
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>
Window:
<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>
Code-behind:
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());
}
}
}
Som du kan se, gemmer vi tre forskellige "Hallo verden!" beskeder: En i App.xaml, en i vinduet og en lokalt for det primære panel. Interfacet består af en knap og en ListBox.
I code-behind håndterer vi klik-hændelsen fra knappen, hvor vi tilføjer hver af tekststrengene til ListBox som vist i skærmbilledet. Vi bruger FindResource() metoden, hvilket vil returnere ressourcen som et object (hvis fundet), og derefter laver vi det om til en streng, som vi ved, det er, ved at bruge ToString() metoden.
Bemærk hvordan vi bruger FindResource() metoden på forskellige områder - først på panelet, derefter på vinduet og endelig på det nuværende Application object. Det giver mening at lede efter ressourcen der, hvor vi ved den er, men som tidligere nævnt søges opad i hierarkiet, hvis en ressource ikke bliver fundet. Så i princippet kunne vi have brugt FindResource() metoden på panelet i alle tre tilfælde eftersom den ville have fortsat op til vinduet og derefter til applikationsniveau, hvis ikke fundet.
Det samme er ikke tilfældet den anden vej rundt - søgningen navigerer ikke ned i træet, så du kan ikke starte med at lede efter en ressource på applikationsniveau, hvis den er defineret lokalt for en kontrol eller et vindue.