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.