This article has been localized into Italian by the community.
Risorse
WPF introduce un concetto molto utile: la possibilità di memorizzare i dati come risorsa, localmente per un controllo, localmente per l'intera finestra o globalmente per l'intera applicazione. I dati possono essere praticamente ciò che si desidera, dalle informazioni effettive a una gerarchia di controlli WPF. Questo ti permette di posizionare i dati in un posto e poi usarli da o in molti altri posti, il che è molto utile.
Il concetto è molto usato per stili e modelli, di cui parleremo più avanti in questo tutorial, ma come verrà illustrato in questo capitolo, puoi usarlo anche per molte altre cose. Consentitemi di dimostrarlo con un semplice esempio:
<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>
Le risorse hanno una chiave, tramite l'attributo x: Key, che ti permette di fare riferimento ad altre parti dell'applicazione usando questa chiave, in combinazione con l'estensione di markup StaticResource. In questo esempio, ho appena creato una semplice stringa, che poi utilizzo da due diversi comandi TextBlock.
StaticResource vs. DynamicResource
Negli esempi fino ad ora, ho utilizzato l'estensione di markup StaticResource per fare riferimento a una risorsa. Tuttavia, esiste un'alternativa, in forma di DynamicResource.
La differenza principale è che una risorsa statica viene risolta una sola volta, che è nel punto in cui viene caricato XAML. Se la risorsa viene quindi modificata in seguito, questa modifica non si rifletterà dove hai usato StaticResource.
Una DynamicResource, d'altra parte, viene risolta una volta che è effettivamente necessaria, e poi di nuovo se la risorsa cambia. Pensala come se fosse un legame ad un valore statico rispetto ad un legame ad una funzione che monitora questo valore e te lo invia ogni volta che viene cambiato - non è esattamente come funziona, ma dovrebbe darti un'idea di quando utilizzarle. Le risorse dinamiche ti consentono anche di utilizzare risorse che non sono nemmeno presenti durante la fase di progettazione, ad es. se le aggiungi da Codice durante l'avvio dell'applicazione.
Altri tipi di risorse
Condividere una semplice stringa è stato facile, ma puoi fare molto di più. Nel prossimo esempio, memorizzerò anche una serie completa di stringhe, insieme a un pennello sfumato da utilizzare per lo sfondo. Questo dovrebbe darti un'idea abbastanza precisa di quanto puoi fare con le risorse:
<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>
Questa volta, abbiamo aggiunto un paio di risorse extra, in modo che la nostra finestra contenga ora una stringa semplice, una serie di stringhe e un LinearGradientBrush. La stringa viene utilizzata per l'etichetta, la matrice di stringhe viene utilizzata come elementi per il controllo ComboBox e il pennello sfumato viene utilizzato come sfondo per l'intera finestra. Quindi, come puoi vedere, praticamente tutto può essere memorizzato come risorsa.
Risorse locali e applicative
Per ora, abbiamo memorizzato le risorse a livello di finestra, il che significa che è possibile accedervi da tutta la finestra.
Se hai solo bisogno di una determinata risorsa per un controllo specifico, puoi renderlo più locale aggiungendolo a questo controllo specifico, invece della finestra. Funziona esattamente nello stesso modo, con la sola differenza che ora puoi accedere solo dall'ambito del controllo in cui lo hai inserito:
<StackPanel Margin="10">
<StackPanel.Resources>
<sys:String x:Key="ComboBoxTitle">Items:</sys:String>
</StackPanel.Resources>
<Label Content="{StaticResource ComboBoxTitle}" />
</StackPanel>
In questo caso aggiungiamo la risorsa allo StackPanel e quindi la usiamo nel suo controllo figlio, l'etichetta. Anche altri controlli all'interno dello StackPanel avrebbero potuto utilizzarla, proprio come questo controllo figlio. I controlli al di fuori di questo particolare StackPanel, invece, non avrebbero potuto avervi accesso.
Se è necessario accedere alla risorsa da diverse finestre, anche questo è possibile. Il file App.xaml può contenere risorse proprio come la finestra e qualsiasi tipo di controllo WPF e quando le si archivia in App.xaml, sono accessibili globalmente in tutte le finestre e i controlli utente del progetto . Funziona esattamente allo stesso modo di quando la si memorizza e la si usa da una finestra:
<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>
Anche l'utilizzo è lo stesso: WPF incrementerà automaticamente l'ambito, dal controllo locale alla finestra e quindi ad App.xaml, per trovare una determinata risorsa:
<Label Content="{StaticResource ComboBoxTitle}" />
Risorse dal codice
Finora, abbiamo acceduto a tutte le nostre risorse direttamente da XAML, utilizzando un'estensione di markup. Tuttavia, è possibile accedere alle risorse anche da Codice, cosa che può essere utile in diverse situazioni. Nell'esempio precedente, abbiamo visto come possiamo archiviare le risorse in diversi posti, quindi in questo esempio accediamo a tre diverse risorse da Codice, ciascuna memorizzata in un ambito diverso:
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());
}
}
}
Quindi, come puoi vedere, memorizziamo tre diversi messaggi "Hello, world!" : uno in App.xaml, uno all'interno della finestra e uno localmente per il pannello principale. L'interfaccia è composta da un pulsante e un ListBox.
Nel codice gestiamo l'evento click del pulsante, in cui aggiungiamo ciascuna delle stringhe di testo al ListBox, come si vede sullo screenshot. Usiamo il metodo FindResource (), che restituirà la risorsa come oggetto (se trovato), e quindi lo trasformeremo nella stringa che conosciamo usando il metodo ToString ().
Nota come utilizziamo il metodo FindResource () in diversi ambiti: prima sul pannello, poi sulla finestra e poi sull'oggetto Application. Ha senso cercare una risorsa che sappiamo esistere, ma come già accennato, se una risorsa non viene trovata, la ricerca avanza nella gerarchia, quindi in sostanza avremmo potuto usare il metodo FindResource () sul pannello in tutti e tre i casi, dal momento che avrebbe continuato fino alla finestra e in seguito fino al livello dell'applicazione, se non trovato.
Lo stesso non è vero al contrario, la ricerca non discende l'albero gerarchico. Non è quindi possibile iniziare a cercare una risorsa a livello di applicazione se questa risorsa è stata definita a livello di controllo o finestra.