[3] Il ritorno dello HockeyPlayer (data-binding con WPF)
Ci sono diversi metodi per rendere un po’ più gradevole l’interfaccia della nostra applicazione. Adesso la ListBox mostra ogni HockeyPlayer mostrando solo il nome – comportamento, abbiamo detto, dovuto al fatto che abbiamo fatto l’override del metodo ToString() della nostra classe. Con WPF possiamo andare ben oltre. Chi sta leggendo la mia serie di post su Flickr ne sa qualcosa. 🙂
Questo diventa realizzabile fornendo un template per ogni item che vogliamo visualizzare sulla ListBox. Questo template può essere un Panel di qualche tipo, che contiene altri controlli, tutti bindati a determinate proprietà della classe HockeyPlayer. Vediamo bene e con calma come farlo in pratica. Lo XAML è il seguente:
<Window x:Class="MyItemTemplate.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:a="clr-namespace:MyItemTemplate" Title="MyItemTemplate" Loaded="Window1_Loaded" Width="390" Height="430"> <Window.Resources> <a:HockeyPlayers x:Key="players" /> </Window.Resources> <StackPanel> <ListBox Name="lstPlayers" ItemsSource="{Binding Source={StaticResource players}, Path=HockeyPlayer}" /> </StackPanel> </Window>
Alla Window ho aggiunto una risorsa la cui key è players, che viene utilizzata come ItemsSource della ListBox. Nell’evento Loaded ottengo il riferimento alla risorsa, che è di tipo HockeyPlayers. Trattandosi di una lista, la popolo con 10 HockeyPlayer a caso e la riassegno alla proprietà ItemsSource della ListBox per trovamela popolata. Notare l’utilizzo del Binding: imposto il Source – dicendo che si tratta della risorsa players – ed imposto anche Path, che serve a specificare il tipo che viene bindato su ciascun Item. In questo caso, si specifica che ogni Item appartiene al tipo HockeyPlayer.
E’ arrivata l’ora di assegnare un template alla ListBox. Per farlo, è sufficiente lavorare sulla proprietà ItemTemplate della ListBox, impostandola ad esempio così:
<ListBox Name="lstPlayers" ItemsSource="{Binding Source={StaticResource players}, Path=HockeyPlayer}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Margin="4" Orientation="Horizontal"> <TextBox Text="{Binding Path=Name}" Margin="4" Width="120" /> <TextBox Margin="4" Text="{Binding Path=Weight}" Background="LightCoral" Width="30" /> <TextBlock Margin="4" Text="{Binding ElementName=sldHeight, Path=Value}" Width="60" /> <Slider Name="sldHeight" Value="{Binding Path=Height}" Minimum="140" Maximum="230" Width="120" /> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
Fantastico! Dunque, vediamo cosa è successo. Assegniamo la proprietà ItemTemplate della ListBox: il template è composto da uno StackPanel che contiene 3 TextBox ed uno Slider. La prima TextBox visualizza il nome del giocatore, mentre la seconda il suo peso. La terza TextBox e lo slider lavorano assieme: lo slider è bindato all’altezza del giocatore, mentre la TextBox visualizza il valore effettivo, cosa che lo slider non può fare. In pratica, mentre prima potevamo modificare l’altezza di uno HockeyPlayer solo dopo averlo selezionato dalla ListBox, adesso lo slider compare su ogni riga ed abbiamo subito un impatto un po’ più immediato. Ecco un esempio:
Il tutto senza scrivere una sola linea di codice e, come disse una volta Corrado, con una mano sola. 🙂
Adesso posso tranquillamente agire su ciascuno Slider per modificare l’altezza di ogni giocatore. Vogliamo fare la prova del 9 come alle elementari? Aggiungiamo un pulsante allo StackPanel
<Button Margin="6" Name="btnShowCurrentHeight" Content="Show Height" Click="btnShowCurrentHeight_Click" />
e scriviamo l’event handler specificato:
void btnShowCurrentHeight_Click(object sender, RoutedEventArgs args) { HockeyPlayer pl = lstPlayers.SelectedItem as HockeyPlayer; if (pl != null) { MessageBox.Show(pl.Height.ToString()); } }
Lanciamo l’applicazione, spostiamo un po’ gli Slider a sinistra e a destra, selezioniamo una riga a caso della ListBox e clicchiamo sul pulsante che abbiamo appena creato. Visualizza l’altezza che abbiamo determinato con lo Slider. Se con un DAL riuscissimo a salvare ogni istanza di HockeyPlayer (oppure serializzando su file), salveremmo i valori così come li vediamo sulla UI.
C’è ancora qualcosa da sistemare, primo fra tutti fare in modo che il binding sulla TextBox non visualizzi tutti quei decimali. Ma sarà l’occasione per un successivo post.