Un equilibro tra risorse locali e risorse globali
La maggior parte delle volte ho visto gli stili dei controlli WPF definiti all’interno della Window nella quale poi lo stile stesso viene utilizzato. Lo stile in questo caso può essere utilizzato solo in quella particolare Window nel quale abbiamo creato lo stile. Se lo stile ci serve in altre Window, siamo obbligati a fare un copia & incolla dello XAML dove ci serve, il che non è proprio il massimo.
In WPF possiamo inserire una risorsa all’interno del file App.xaml, all’interno del tag <Application.Resources></Application.Resources>. In questo modo lo stile è globale per tutta l’applicazione. Se inserissimo una risorsa con x:Key=”myTemplate”, potrei far uso di questa risorsa ovunque ce ne sia bisogno. Esiste una via di mezzo? Ovvero: posso definire una risorsa in modo tale che non sia globale, ma che allo stesso tempo non viva solo all’interno di una Window particolare? Posso essere più selettivo, posso dire in qualche modo…qui mi serve e qui no?
Ovvio che sì. Il trucco sta nell’aggiungere un file di risorse in formato XAML, che non fa altro che definire un ResourceDictionary all’interno del quale possiamo inserire tutte le risorse che vogliamo, stili compresi.
Lo XAML può essere editato a mano in tutti i modi che conosciamo:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ctl="clr-namespace:FlickrBrowser.Controls"> <Style TargetType="ListBoxItem"></Style> <Style TargetType="ListBox" x:Key="PhotosetListBoxTemplate"></Style> <Style TargetType="{x:Type ctl:FlickrMenuItem}"></Style> </ResourceDictionary>
In questo caso, il primo stile è associato al tipo ListBoxItem, il secondo è associato al tipo ListBox (ma ha anche una Key) e l’ultimo è associato alla classe FlickrMenuItem. Questa classe eredita da MenuItem: ho seguito i consigli e le correzioni del buon Corrado.
Detto questo, ho avuto un po’ di difficoltà nell’utilizzare questi stili nelle Window della mia applicazione. Innanzitutto, va detta una cosa: la Build Action del file XAML che contiene le risorse (supponiamo…SomeResources.xaml come nell’immagine sopra) va impostato su Resource, che è la cosa più comoda. Vi riporto un blocco tratto direttamente da MSDN che parla proprio di questo argomento:
For resources that are compiled as part of the project, you can use a relative path that refers to the resource location. The relative path is evaluated during compilation. Your resource must be defined as part of the project as a Resource build action. If you include a resource .xaml file in the project as Resource, you do not need to copy the resource file to the output directory, the resource is already included within the compiled application. You can also use Content build action, but you must then copy the files to the output directory and also deploy the resource files in the same path relationship to the executable.
I valori plausibili per la Build Action sono Resource e Content. E non bisogna usare Embedded Resource. Io ho utilizzato Resource.
Nelle Window dove ci interessa utilizzare le risorse occorre importare lo XAML che contiene le risorse che ci servono. Questo si traduce nel prendere una Window qualsiasi all’interno del progetto ed inserire fra le risorse:
<Window x:Class="FlickrBrowser.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Flickr Browser - Search Photoset" Height="600" Width="700" WindowStartupLocation="CenterScreen"> <Window.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="SomeResources.xaml" /> </ResourceDictionary.MergedDictionaries> </Windows.Resources> </Window>
In pratica, si fa un merge tra il ResourceDictionary definito nella Window ed il ResourceDictionary definito nel file di risorse specificato nella proprietà Source. A questo punto tutto comincia a funzionare come al solito: se uno stile è associato ad un tipo, allora quello stile verrà utilizzato, come nel caso di ListBox. Se uno stile ha una Key, è sufficiente referenziarla con StaticResource, e così via.
E’ trovato molto utile tutto questo. Ci saranno n motivi per farlo: quello che mi piace di più è il poter effettivamente definire uno stile e il poterlo riutilizzare ovunque vogliamo, pur mantenendo una sorta di selezione accurata, perchè basta importare dentro ogni Window quella che effettivamente ci serve. Un giusto punto di equilibrio tra risorse locali e risorse globali.
Technorati Tags: programming .NET WPF