Se il codice che produco è passibile di mille critiche, le maschere che mi capita di creare sono indubbiamente e sicuramente delle schifezze immonde.
Il bottone lo metto sempre nella posizione sbagliata, e così le caselle di testo, per non parlare del colore assegnato ai controlli: i miei colleghi diventano matti a sistemare le UI che creo in modo che siano non dico utilizzabili, ma che almeno siano presentabili.
Per questo motivo non mi trovo a mio agio a parlare di aspetto dei controlli UI WPF: semplicemente non è il mio campo !
Però siccome nelle prossime parti occorrerà mettere mano allo stile dei controlli, per lo meno quando si parlerà della validazione dei dati inseriti, occorre che ne scriva qualcosa !
Per ogni elemento WPF è possibile modiifcarne il “look and feel” settandone opportunamente le relative proprietà.
<Button Width="150" FontSize="12" Background="Blue" Content="Sono di bell’aspetto !" />
Invece di definire l’aspetto di ogni singolo controllo è possibile creare uno “stile”, che in pratica è un meccanismo che permette di centralizzare i valori delle proprietà inerenti l’aspetto grafico dei controlli.
Così cambiare l’aspetto grafico dell’intero applicativo diventa facile: invece che intervenire sui singoli controlli è possibile solo agire in una questa parte centralizzata.
Questa parte centralizzata delegata a contenere tra le altre cose le gli stili prende il nome generico di risorsa. In altri termini nel listato XAML è possibile definire in un punto, chiamato appunto risorsa, che sarà delegato a contenere le caratteristiche generali da applicare a tutti gli elementi.
<Window x:Class="WPF001_Layout.WPFStyles" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WPF001_Layout" mc:Ignorable="d" Title="WPFStyles" Height="300" Width="300"> <Window.Resources> <Style TargetType="{x:Type Button}"> <Setter Property="Background" Value="LemonChiffon" /> <Setter Property="FontSize" Value="22" /> </Style> <Style x:Key="ButtonStyle"> <Setter Property="Button.Background" Value="Red" /> <Setter Property="Button.Foreground" Value="White" /> <Setter Property="Button.FontSize" Value="18" /> </Style> </Window.Resources> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <Button Content="Usa lo stile con chiave" Style="{StaticResource ButtonStyle}" Grid.Column="0" Grid.Row="0" /> <Button Content="Uses named style" Grid.Column="0" Grid.Row="1" /> </Grid> </Window>
Come si puà intuire all'interno del nodo Window.Resources, che rappresenta il contenitore delle risorse, sono stati riportati due stili.
L’associazione tra gli elementi e lo stile può essere fatto in due modi.
- Allo stile viene assegnato un identificativo, e solo gli elementi che specificano di voler usare lo stile con quell’indentificativo useranno lo stile definito nelle risorse
- E’ possibile specificare allo stile di essere applicato a tutti gli elementi di un certo tipo.
Per assegnare uno stile a tutti gli elementi di un certo tipo (ad esempio a tutti i bottoni) è necessario usare l'attributo TargetType e assegnare al markup x:type il tipo di controllo WPF destinatario dello stile
Nel caso sopra a tutti i bottoni è stato assegnato uno stile che modiifca il colore di background in un elegante (?) LemonChiffon, mentre la dimensione dei caratteri èstato portato a un sobrio 22.
Diversamente per usare uno stile definito con chiave occorre usare l'attributo x:Key, e quindi i controlli dovranno essere associati a questo tramite Style="{StaticResource }".
Direi che il codice a corredo è abbastanza esplicativo.
Resources
Nel caso visto in precedenza gli stili sono posti all’interno di un nodo risorse collocato nello stesso codice WPF che descrive la maschera.
Partendo dall’osservazione che è difficile che in una maschera un bottone assuma un colore, e in un’altra maschera un colore differente (a meno che non stiate utilizzando un software scritto da me, ma questo è un’altro discorso......) è possibile centralizzare ulteriormente gli stili ponendoli in un file separato a cui tutte le form possano riferirsi.
Per esempio è possibile sfruttare il file App.xaml, che viene creato ad ogni nuovo progetto WPF, e che è delegato oltre che come entry point al lancio dell’applicativo anche come repository di rorse che quindi possono essere utilizzate dall’intera App.
<Application x:Class="StylesAndResources.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" StartupUri="MainWindow.xaml"> <Application.Resources> </Application.Resources> </Application>
Ritengo sia utile spendere due parole in più sulle risorse.
Sinora si è visto l’utilizzo delle risorse come contenitore di stili, ma in realtà questo meccanismo è utilizzato per contenere una miriade di altri dati che possono essere utili all’interno dell’applicativo.
Il codice proposto nel seguito direi che propone bene il concetto che voglio esprimere.
<Window x:Class="WpfApp2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:local="clr-namespace:WpfApp2" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <sys:String x:Key="strHelloWorld">Hello, world!</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> </Window.Resources> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" Text="{StaticResource strHelloWorld}" FontSize="90" /> <ComboBox Grid.Row="1" Grid.Column="0" Height="20" Margin="10,10,10,10" ItemsSource="{StaticResource ComboBoxItems}" /> </Grid> </Window>
Qui per definire la lista delle stringe da proporre in una combo box viene utilizzato la risorsa: analogamente per definire una stringa da proporre in una textblock.
Oss.: Vedremo nel seguito il controllo Textblock: per ora basti sapere che è una specie di label evoluta.