Per far capir meglio le logiche del layout di WPF, che sono molto diverse rispetto al classico Windows Forms, ho preferito elaborare questa immagine:
Questo mi sa che è il mio post più colorato! La window ChooseEmoticon è formata principalmente da una Grid con quattro righe, che corrispondono ai colori giallo (in alto), rosa (al centro), bianco (ehm...un po' più in basso rispetto al centro) e verde+rosso (in basso). In XAML, la dichiarazione della Window è la seguente...
<Window x:Class="VivendoByte.Emoticons.ChooseEmoticon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="VivendoByte Emoticons" Width="400" Height="300" ResizeMode="CanResizeWithGrip">
...dove viene definito il titolo, larghezza ed altezza e la modalità di ridimensionamento. Il tag di Window si chiude in fondo allo XAML. La Grid invece appare nello XAML come segue:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="35"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="25"></RowDefinition>
<RowDefinition Height="60"></RowDefinition>
</Grid.RowDefinitions>
...
...
</Grid>
Come si vede, la Grid ha quattro righe: alcune hanno alltezza fissa (35, 25 e 60), mentre una ha un'altezza definita come * (asterisco, star o come lo chiamate voi). Al posto dei "..." ci va un altro blocco di XAML, che definisce il contenuto della Grid (TextBlock e quant'altro).
<TextBlock VerticalAlignment="Center" FontSize="16" Margin="6" Grid.Row="0" Grid.Column="0">
Clicca sull'emoticon che vuoi inserire...
</TextBlock>
<TextBlock Name="emoticonsAvaiable" VerticalAlignment="Center" FontSize="12" Margin="6" Grid.Row="2" Grid.Column="0">
Le emoticon(s) disponibili sono xxx.
</TextBlock>
<WrapPanel Name="MainPanel" ItemHeight="70" ItemWidth="70" Grid.Column="0" Grid.Row="1">
</WrapPanel>
I primi due blocchi di XAML definiscono due TextBlock: uno per la scritta "Clicca sull'emoticon che vuoi inserire..." ed un altro per "Le emoticon(s) disponibili sono xxx.". Poi viene inserito un WrapPanel, che conterrà le emoticons: si trova nella cella (0,1) della Grid - quella ad altezza variabile. Ciò significa che quando la finestra viene ridimensionata, lo WrapPanel si ridimensiona automaticamente. I Children contenuti nello WrapPanel vengono automaticamente riposizionati (arrange) in base alle dimensioni correnti.
Il blocco di XAML qui sopra determina il contenuto della prima, seconda e terza riga. La quarta riga (quella verde+rosso) è formata a sua volta da un DockPanel. Docckato a sinistra (area verde) c'è un MediaElement, che serve per fare la preview di un'emoticon. Dockkati a destra (area rossa) invece abbiamo i due Button Annulla ed Inserisci. Il blocco di XAML per fare tutto questo è il seguente:
<DockPanel Grid.Column="0" Grid.Row="3">
<MediaElement DockPanel.Dock="Left" Margin="10" Width="70" Name="emoticonPreview"></MediaElement>
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal" FlowDirection="RightToLeft">
<Button Margin="10" Width="70" IsEnabled="False" IsCancel="False" IsDefault="True" Name="btnInsert" Click="InsertEmoticon">Inserisci</Button>
<Button Margin="10" Width="70" IsCancel="True" Name="btnCancel">Annulla</Button>
</StackPanel>
</DockPanel>
Giocando un po' con i margini, si ottiene una buona impaginazione degli elementi e dei controlli sulla finestra. Notare che ai Button vengono impostate alcune proprietà (IsEnabled, IsCancel, IsDefault e soprattutto il Name) ed un handler per l'evento Click (Button btnInsert), che si chiama InsertEmoticon. Il codice per questo handler è ovviamente definito nel code-behind, insieme ad un altro po' di roba di cui parleremo la prossima volta.