Un behavior per gestire il Foreground di una ListBox in Silverlight

di Marco Leoncini, in Silverlight,

La ListBox è senza ombra di dubbio uno dei controlli più utilizzati di Silverlight, sia per le funzionalità, come la sincronizzazione con le collezioni che implementano ICollectionView, sia per la facilità con la quale è possibile impostarne l'aspetto.

Utilizzando le caratteristiche del Visual State Manager è possibile personalizzare, anche in maniera estrema, l'aspetto della ListBox. Ci sono però alcuni particolari, come il colore di Foreground, che è difficile personalizzare se non limitando la possibilità di riutilizzare la template.

È utile ricordare l'anatomia che determina l'aspetto si una ListBox: la proprietà ItemTemplate determina la template da utilizzare per visualizzare i dati, mentre ItemContainerStyle determina l'aspetto del contenitore.

Un modo per modificare la selezione ed il colore di Foreground di un ListBoxItem è modificarne la template, e sostituire il ContentPresenter con una TextBlock. Questa modifica è più che lecita, ma di fatto impedisce di utilizzare qualsiasi tipo di DataTemplate ed è poco riutilizzabile.

Per aggirare questo problema possiamo realizzare un semplice Behavior, creiamo quindi una nuova classe che estenda il tipo Behavior:

public class SetSelectedItemForegroundBehavior : Behavior<ListBox>{}

Abbiano assegnato al Typed Argument il tipo ListBox, questo limita l'utilizzo di questo behavior al tipo ListBox e tipizza fortemente la proprietà AssociatedObject che il tipo Behavior<T> espone.

Proseguiamo dichiarando un campo di tipo Brush, nel quale salveremo il colore corrente dell'elemento non ancora selezionato e una DependendyProperty per impostare il colore che deve assumere dopo la selezione.

private Brush originalBush;
public Color SelectedColorProperty
{
  get { return ( Color)GetValue(SelectedColorPropertyProperty); }
  set { SetValue(SelectedColorPropertyProperty, value); }
}

Eseguiamo l'override del metodo OnAttached e registriamoci per l'evento SelectionChanged:

protected override void OnAttached()
{
  base.OnAttached();
  this.AssociatedObject.SelectionChanged += new SelectionChangedEventHandler(AssociatedObject_SelectionChanged);
}

Il metodo è abbastanza semplice e si limita a recuperare l'elemento selezionato e ad impostarne il colore oltre a reimpostare il colore originale dell'elemento deselezionato:

protected override void OnAttached()
{
  base.OnAttached();
  this.AssociatedObject.SelectionChanged += new SelectionChangedEventHandler(AssociatedObject_SelectionChanged);
}

void AssociatedObject_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
  if (e.AddedItems.Count > 0)
  {
    if (e.AddedItems[0] is ListBoxItem)
    {
      ListBoxItem item = (ListBoxItem)e.AddedItems[0];
      originalBush = item.Foreground;
      item.Foreground = new SolidColorBrush(SelectedColorProperty);
    }
    else
    { 
        Action a = null;
        a = () =>
        {
        ListBoxItem listBoxItem = AssociatedObject.ItemContainerGenerator.ContainerFromItem(e.AddedItems[0]) as ListBoxItem;
         if (listBoxItem != null)
            listBoxItem.Foreground = new SolidColorBrush(Colors.White);
          else
             Dispatcher.BeginInvoke(a);
          };
        Dispatcher.BeginInvoke(a);
    }
  }
  if (e.RemovedItems.Count > 0)
  {
    if (e.RemovedItems[0] is ListBoxItem)
    {
      ((ListBoxItem)e.RemovedItems[0]).Foreground = originalBush;
    }
    else
    {
     Action a = null;
     a = () =>
     {
       ListBoxItem listBoxItem = AssociatedObject.ItemContainerGenerator.ContainerFromItem(e.RemovedItems[0]) as ListBoxItem;
         if (listBoxItem != null)
         listBoxItem.Foreground = new SolidColorBrush(Colors.Black);
         else
          Dispatcher.BeginInvoke(a);
         };
       Dispatcher.BeginInvoke(a);
    }
  }
}

L'unica cosa particolare da notare è l'utilizzo di un ciclo per recuperare il ListBoxItem in caso la lista sia creata da DataBind piuttosto che da XAML. Questo espediente è necessario in quanto non è possibile determinare a priori quando il ListBoxItem verrà creato, poiché tutto il processo è asincrono.

Non ci resta che compilare il nostro Behavior e associarlo alla nostra ListBox, ed in seguito impostare il colore da associare all'elemento selezionato.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi