Ricerca…
Ciao 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. Ciò ti consente di posizionare i dati in un unico posto e utilizzarli da o in molti altri luoghi, il che è molto utile. Il concetto è molto usato per stili e modelli.
<Window x:Class="WPFApplication.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>
Alle risorse viene assegnata una chiave, utilizzando l'attributo x: Key, che consente di fare riferimento ad altre parti dell'applicazione utilizzando questo tasto, in combinazione con l'estensione di markup StaticResource. In questo esempio, ho appena archiviato una semplice stringa, che poi utilizzo da due diversi controlli TextBlock.
Tipi di risorse
Condividere una semplice stringa era facile, ma puoi fare molto di più. In questo 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="WPFApplication.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
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 dal suo controllo figlio, l'etichetta. Altri controlli all'interno di StackPanel potrebbero averlo utilizzato, proprio come i bambini di questi controlli figlio sarebbero stati in grado di accedervi. I controlli al di fuori di questo particolare StackPanel non avrebbero accesso ad esso, però.
Se è necessaria la possibilità di 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 si memorizza e si usa da una finestra:
<Application x:Class="WpfSamples.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="WPFApplication/ExtendedResourceSample.xaml">
<Application.Resources>
<sys:String x:Key="ComboBoxTitle">Items:</sys:String>
</Application.Resources>
</Application>
Anche l'utilizzo è lo stesso: WPF aumenterà automaticamente l'ambito, dal controllo locale alla finestra e quindi ad App.xaml, per trovare una determinata risorsa:
<Label Content="{StaticResource ComboBoxTitle}" />
Risorse da Code-behind
In questo esempio, accediamo a tre diverse risorse da Code-behind, ciascuna memorizzata in un ambito diverso
App.xaml:
<Application x:Class="WpfSamples.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="WPFApplication/ResourcesFromCodeBehindSample.xaml">
<Application.Resources>
<sys:String x:Key="strApp">Hello, Application world!</sys:String>
</Application.Resources>
</Application>
Finestra:
<Window x:Class="WpfSamples.WPFApplication.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 WpfSamples.WPFApplication
{
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 "Hello, world!" messaggi: 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.
In Code-behind, 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 () su diversi ambiti: prima sul pannello, poi sulla finestra e poi sull'oggetto Application corrente. Ha senso cercare la risorsa in cui sappiamo che è, ma come già accennato, se una risorsa non viene trovata, la ricerca avanza nella gerarchia, quindi in principio 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 naviga giù dall'albero, quindi non è possibile iniziare a cercare una risorsa a livello di applicazione, se è stata definita localmente per il controllo o per la finestra.