This article is currently in the process of being translated into Catalan (~52% done).
Resources
WPF introdueix un concepte molt útil: La capacitat d'emmagatzemar dades com si fossin un recurs, ja sigui localment per un control, localment per tota una finestra o globalment per tota l'aplicació. Les dades poden ser pràcticament el que es vulgui, desde informació real fins a un jerarquia de controls WPF. Això permet posar dades en un lloc i fer-les servir des de qualsevol altre, el que esdevé realment útil.
Aquest concepte es fa servir força pels estils i les plantilles, que es discutirà més endavant en aquest tutorial però, com s'il·lustrarà en aquest capítol, es pot fer servir per altres propòsits també. Deixa'm demostrar-ho amb un exemple:
<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>

Als recursos se'ls assigna una clau, fent servir l'atribut x:Key, que permet referenciar-los des d'altres parts de l'aplicació fent servir aquesta clau, en combinació amb la marca d'extensió StaticResource. En aquest exemple només s'emmagatzema una cadena alfanumérica, que es fa servir des de diferents controls TextBox.
StaticResource vs. DynamicResource
Fins ara, en els exemples, he fet servir la marca d'extensió StaticResource per referenciar un recurs. No obstan això, existeix una alternativa, en forma de DynamicResource.
La diferencia més gran és que un recurs estàtic es resol només una vegada, en el moment en que el XAML es carrega. Si el recurs es canvia més tard, aquest canvi no es veurà reflectit allà on tu has utilitzat el recurs estàtic.
D'altra banda, un DynamicResource es resol quan realment es necessita, i de nou si el recurs canvia. Penseu-ho com a una vinculació a un valor estàtic versus una vinculació a una funció que controla aquest valor i us l'envia cada vegada que ha canviat - no és exactament com funciona, però us hauria de donar una millor idea de quan utilitzar què. Els recursos dinàmics també us permeten utilitzar recursos que ni tan sols hi són durant el temps de disseny, per exemple, si els afegiu des de Code-behind durant l'inici de l'aplicació.
Més tipus de Resources
Compartir una cadena senzilla era fàcil, però pots fer molt més. En el següent exemple, també emmagatzemaré una matriu completa de cadenes, juntament amb un pinzell de degradat que s'utilitzarà per al fons. Això us hauria de donar una idea bastant bona de què podeu fer amb els Resources:
<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>

Aquesta vegada, hem afegit un parell de recursos addicionals, de manera que la nostra finestra ara conté una cadena simple, una matriu de cadenes i una LinearGradientBrush. El la cadena s'utilitza per a l'etiqueta, la matriu de cadenes s'utilitza com a elements per al control ComboBox i el pinzell de degradat s'utilitza com a fons per a tot el conjunt finestra. Així que, com podeu veure, gairebé qualsevol cosa es pot emmagatzemar com a Resource.
Resources locals i d'aplicació
Per ara, tenim recursos emmagatzemats a nivell de finestra, el que significa que podeu accedir-hi des de tota la finestra.
Si només necessiteu un recurs donat per a un control específic, podeu fer-lo més local afegint-lo a aquest control específic, en lloc de la finestra. Funciona exactament de la mateixa manera, l'única diferència és que ara només es pot accedir des de l'interior de l'àmbit del control on es posa:
<StackPanel Margin="10">
<StackPanel.Resources>
<sys:String x:Key="ComboBoxTitle">Items:</sys:String>
</StackPanel.Resources>
<Label Content="{StaticResource ComboBoxTitle}" />
</StackPanel>
In this case, we add the resource to the StackPanel and then use it from its child control, the Label. Other controls inside of the StackPanel could have used it as well, just like children of these child controls would have been able to access it. Controls outside of this particular StackPanel wouldn't have access to it, though.
If you need the ability to access the resource from several windows, this is possible as well. The App.xaml file can contain resources just like the window and any kind of WPF control, and when you store them in App.xaml, they are globally accessible in all of windows and user controls of the project. It works exactly the same way as when storing and using from a 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>
Using it is also the same - WPF will automatically go up the scope, from the local control to the window and then to App.xaml, to find a given resource:
<Label Content="{StaticResource ComboBoxTitle}" />
Resources from Code-behind
So far, we've accessed all of our resources directly from XAML, using a markup extension. However, you can of course access your resources from Code-behind as well, which can be useful in several situations. In the previous example, we saw how we could store resources in several different places, so in this example, we'll be accessing three different resources from Code-behind, each stored in a different scope:
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());
}
}
}

So, as you can see, we store three different "Hello, world!" messages: One in App.xaml, one inside the window, and one locally for the main panel. The interface consists of a button and a ListBox.
In Code-behind, we handle the click event of the button, in which we add each of the text strings to the ListBox, as seen on the screenshot. We use the FindResource() method, which will return the resource as an object (if found), and then we turn it into the string that we know it is by using the ToString() method.
Notice how we use the FindResource() method on different scopes - first on the panel, then on the window and then on the current Application object. It makes sense to look for the resource where we know it is, but as already mentioned, if a resource is not found, the search progresses up the hierarchy, so in principal, we could have used the FindResource() method on the panel in all three cases, since it would have continued up to the window and later on up to the application level, if not found.
The same is not true the other way around - the search doesn't navigate down the tree, so you can't start looking for a resource on the application level, if it has been defined locally for the control or for the window.