This article has been localized into French by the community.
Ressources
WPF introduit un concept très pratique : La possibilité de sauvegarder des données en tant que ressource, aussi bien localement pour un contrôle, que localement pour la fenêtre entière ou encore globalement pour l'application entière. Les données peuvent être tout ce que vous voulez, depuis des informations en tant que telles, à une hiérarchie de contrôles WPF. Cela vous permet de placer des données dans un endroit spécifique et de les utiliser ensuite depuis cet endroit ou n'importe quel autre, ce qui est très utile.
Ce concept est beaucoup utilisé pour les styles et les modèles, ce dont nous allons parler plus tard dans ce tutoriel, mais de la même façon que c'est illustré dans ce chapitre, vous pouvez l'utiliser tout aussi bien pour beaucoup d'autres choses. Laissez-moi vous démontrer cela avec un exemple simple :
<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>
Les ressources sont données au moyen d'une clé, en utilisant l'attribut x:Key, ce qui vous permet de la référencer depuis d'autres parties de l'application en utilisant cette clé, en combinaison avec l'extension de balisage StaticResource. Dans cet exemple, je sauvegarde juste une simple chaine de caractères, que j'utilise ensuite depuis deux différents contrôles TextBlock.
StaticResource comparé à DynamicResource
Dans les exemples précédents, j'ai utilisé l'extension de balisage StaticResource pour référencer une ressource. Cependant, une alternative existe, sous la forme du DynamicResource.
La principale différence est qu'une ressource statique n'est résolue qu'une seule fois au moment où le XAML est chargé. Si la ressource est ensuite modifiée, ce changement ne sera pas reflété là où vous avez utilisé la StaticResource.
Une Ressource Dynamique d'autre part, est déterminée une fois qu'elle est réellement nécessaire, et de nouveau si la ressource change. Pensez-y comme un lien à une valeur statique vs. un lien à une fonction qui surveille cette valeur et vous l'envoie à chaque fois qu'elle est modifiée - ce n'est pas exactement comment cela qu'elle fonctionne, mais cela devrait vous donner une meilleure idée de quand et comment l'utiliser. Les ressources dynamiques vous permettent également d'utiliser des ressources qui ne sont même pas là pendant la conception, par exemple si vous les ajoutez depuis le Code-behind pendant le démarrage de l'application.
Autres types de ressources
Partager une simple chaîne de caractères était facile, mais vous pouvez faire beaucoup plus. Dans l'exemple suivant, je vais aussi stocker un tableau complet de chaînes de caractères, ainsi qu'une palette de couleurs à utiliser pour l'arrière-plan. Cela devrait vous donner une assez bonne idée de ce que vous pouvez faire avec les ressources :
<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>
Cette fois, nous avons ajouté quelques ressources supplémentaires, de sorte que notre Fenêtre contient maintenant une simple chaîne de caractères, un tableau de chaînes de caractères et un LinearGradientBrush. La chaîne de caractères est utilisée pour l'étiquette, le tableau de chaînes de caractères est utilisé comme éléments pour le contrôle ComboBox et la brosse à dégradé est utilisée comme arrière-plan pour l'ensemble de la fenêtre. Ainsi, comme vous pouvez le voir, à peu près tout peut être stocké comme une ressource.
Ressources locales et à la portée de l'application
Pour l'instant, nous avons stocké les ressources au niveau de la fenêtre, ce qui signifie que vous pouvez y accéder de partout dans la fenêtre.
Si vous n'avez besoin que d'une ressource donnée pour un contrôle spécifique, vous pouvez la rendre plus locale en l'ajoutant à ce contrôle spécifique au lieu de la fenêtre. Cela fonctionne exactement de la même manière, la seule différence étant que vous ne pouvez désormais accéder qu'à partir de l'intérieur du champ d'application du contrôle où vous l'avez placé :
<StackPanel Margin="10">
<StackPanel.Resources>
<sys:String x:Key="ComboBoxTitle">Items:</sys:String>
</StackPanel.Resources>
<Label Content="{StaticResource ComboBoxTitle}" />
</StackPanel>
Dans ce cas, nous ajoutons la ressource au StackPanel et l'utilisons ensuite à partir de son contrôle enfant, le Label. D'autres contrôles à l'intérieur du StackPanel auraient pu l'utiliser également, tout comme les enfants de ces contrôles enfants auraient pu y accéder. Les contrôles en dehors de ce StackPanel particulier n'y auraient pas accès, cependant.
Si vous avez besoin d'accéder à la ressource à partir de plusieurs fenêtres, cela est également possible. Le fichier App.xaml peut contenir des ressources comme la fenêtre et n'importe quel type de contrôle WPF, et lorsque vous les stockez dans App.xaml, elles sont globalement accessibles dans toutes les fenêtres et les contrôles utilisateur du projet. Il fonctionne exactement de la même manière que lors du stockage et de l'utilisation à partir d'une fenêtre :
<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>
L'utiliser fonctionnera également de la même manière - WPF ira automatiquement vers le haut de la portée, du contrôle local à la fenêtre et ensuite à App.xaml, pour trouver une ressource donnée :
<Label Content="{StaticResource ComboBoxTitle}" />
Ressources issues de Code-behind
Jusqu'à présent, nous avons accédé à toutes nos ressources directement à partir de XAML, en utilisant une extension de balisage. Cependant, vous pouvez bien sûr accéder à vos ressources à partir de Code-behind, ce qui peut être utile dans plusieurs situations. Dans l'exemple précédent, nous avons vu comment nous pouvions stocker des ressources à plusieurs endroits différents, donc dans cet exemple, nous allons accéder à trois ressources différentes à partir de Code-behind, chacune stockée dans une portée différente :
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());
}
}
}
Ainsi, comme vous pouvez le voir, nous stockons trois messages "Hello, world" ! Un dans App.xaml, un à l'intérieur de la fenêtre, et un localement pour le panneau principal. L'interface se compose d'un bouton et d'une ListBox.
Dans Code-behind, nous utilisons l'événement click du bouton, dans lequel nous ajoutons chacune des chaînes de texte à la ListBox, comme on le voit sur la capture d'écran. Nous utilisons la méthode FindResource(), qui retournera la ressource en tant qu'objet (si elle est trouvée), et ensuite nous la transformons en une chaîne de caractères dont on sait qu'elle en est une, en utilisant la méthode ToString().
Remarquez comment nous utilisons la méthode FindResource() sur différentes portées - d'abord sur le Panel, puis sur la fenêtre et ensuite sur l'objet Application courant. Il est logique de chercher la ressource là où nous savons qu'elle se trouve, mais comme déjà mentionné, si une ressource n'est pas trouvée, la recherche progresse vers le haut de la hiérarchie, donc en principe, nous aurions pu utiliser la méthode FindResource() sur le Panel dans les trois cas, puisqu'elle aurait continué jusqu'à la fenêtre et plus tard jusqu'au niveau de l'application, si elle n'avait pas été trouvée.
La même chose n'est pas vraie dans l'autre sens - la recherche ne descend pas dans l'arborescence, donc vous ne pouvez pas commencer à chercher une ressource au niveau de l'application, si elle a été définie localement pour le contrôle ou pour la fenêtre.