Template per evidenziare il SelectedItem di una ListBox
Alla fine della sessione di Corrado agli ultimi Community Days sul data-binding di WPF, gli ho chiesto se fosse possibile cambiare (e se sì, come) il template che WPF utilizza per evidenziare l’Item corrente su una ListBox. Il template di default è il classico blu, come quello che si vede nello screenshot qui sotto:
A volte potrebbe essere utile e carino definire un nostro template con cui far vedere all’utente quale degli elementi elencati nella ListBox è quello selezionato. Corrado mi parlò di una cosa…che adesso ovviamente non mi viene in mente… Ma ricordo anche che consigliò di sottoscrivere il blog www.beacosta.com che lui stesso definì come una risorsa piuttosto importante per tutto quello che riguarda WPF. Manco a farlo apposta, il post del 1° Aprile scorso parla proprio di questa cosa.
Non voglio fare banalmente il copia & incolla dello XAML che compare nel post, per questo basta che cliccate sul link qui sopra, cercate un attimo l’ultimo snippet di codice ed il gioco è fatto. Voglio farvi vedere quello che ho realizzato io partendo dagli spunti e dalle considerazioni che ho trovato nel post.
La logica riguarda principalmente il trigger, che scatta nel momento in cui la proprietà IsSelected del singolo ListBoxItem diventa true. Quando questa condizione è verificata, vengono eseguiti uno o più setter su una o più proprietà. Nel caso dell’esempio di prima l’ellisse serve ad evidenziare un pianeta, mentre nel mio caso vorrei fare qualcosa di diverso, ovvero cambiare semplicemente il colore di sfondo. Il blocco XAML è riportato qui sotto:
<Style TargetType="ListBoxItem"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListBoxItem}"> <Grid> <Rectangle x:Name="selectedItem" Margin="-10" StrokeThickness="2" Height="{TemplateBinding Height}" Width="{TemplateBinding Width}" /> <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsSelected" Value="true"> <Setter Property="Stroke" TargetName="selectedItem" Value="LightGreen"/> <Setter Property="Fill" TargetName="selectedItem"> <Setter.Value> <LinearGradientBrush StartPoint="0,0.1" EndPoint="1,0.1"> <GradientStop Color="LightGreen" Offset="0.0" /> <GradientStop Color="White" Offset="1.0" /> </LinearGradientBrush> </Setter.Value> </Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
Il template è composto da una Grid, che contiene una sola colonna ed una sola riga…di conseguenza…una sola cella. In questa cella sono presenti due elementi: un Rectangle ed un ContentPresenter. Quest’ultimo è l’area che contiene il contenuto effettivo del ListBoxItem. Il rettangolo invece non ha bordo e soprattutto non è riempito: in altre parole, inizialmente non è visibile e l’utente proprio non lo vede.
Quando viene selezionato un ListBoxItem dalla ListBox, si scatena il trigger che non fa altro che settare lo Stroke del rettangolo a LightGreen, e settare il Fill con un effetto gradiente dal LightGreen al White. Il rettangolo copre completamente tutta l’area necessaria a contenere il ListBoxItem. L’effetto finale, al contrario di quello che dice Roberto (Rob, sto scherzando…sono d’accordo con te!), questa volta è davvero molto gradevole!
Insomma, adesso quando seleziono un elemento dalla ListBox non compare in uno stupido blu sempre uguale…e soprattutto ho imparato come usare un template custom, che vuol dire poter utilizzare immagini e stili per fare il tutto molto più gradevole. ‘Sto WPF, se non si fosse capito, mi intrippa proprio.
Technorati Tags: flickr programming WPF .NET