Dove siamo rimasti:
L’ultima volta ci siamo lasciati con due requisiti in sospeso:
  • essere in grado di modificare un indirizzo;
  • essere in grado di eliminare un indirizzo;
Requsiti che sappiamo introducono le seguenti necessità:
  • come tenere traccia dell’elemento selezionato nella lista degli indirizzi?
  • come visualizzare i dati dell’elemento selezionato?
  • come gestire un’azione, la cancellazione in questo caso?
SelectedItem binding
Tenere traccia di quale sia l’indirizzo selezionato è un’operazione relativamente banale:
private AddressViewModel _selectedAddress = null;
public AddressViewModel SelectedAddress
{
    get { return this._selectedAddress; }
    set
    {
        if( value != this.SelectedAddress )
        {
            this._selectedAddress = value;
            this.OnPropertyChanged( () => this.SelectedAddress );
        }
    }
}
Anche se ci pone di fronte ad una prima decisione: chi è responsabile di tenere traccia di quale sia l’elemento selezionato?
  • PersonViewModel?
  • o MainViewModel?
la decisione è tutto tranne che scontata e men che meno universale, dipende molto dal contesto e in questo specifico caso direi che per ora possiamo assegnare tranquillamente questa responsabilità a MainViewModel.
Le modifiche da apportare allo xaml sono altrettanto banali:
<ListView Grid.ColumnSpan="2" Grid.Row="4" Margin="12" 
            ItemsSource="{Binding Path=Person.Addresses}"
            SelectedItem="{Binding Path=SelectedAddress}"
            HorizontalAlignment="Stretch"
            VerticalAlignment="Stretch">
Ci limitiamo a chiedere alla ListView di tracciare quale sia l’lemento corrente mettendo in binding la proprietà SelectedItem con la nostra proprietà SelectedAddress.
Visivamente a questo punto non è cambiato nulla ma se mettiamo un breakpoint sul setter della nostra proprietà al variare dell’elemento selezionato il motore di binding viene da noi a impostare il nuovo valore.

Naturalmente il binding è bidirezionale quindi possiamo preimpostare un SelectedAddress e vedere che la ListView si adegua di conseguenza:
this.SelectedAddress = this.Person.Addresses.FirstOrDefault();
image
SelectedItem “reverse” binding
Ora che abbiamo un elemento selezionato possiamo introdurre nella nostra vista master-details la porzione di UI per l’editing e ringraziare il motore di databinding di Wpf per averci regalato cotanta potenza:
<TextBox Height="23" 
         HorizontalAlignment="Stretch" 
         Text="{Binding Path=SelectedAddress.Street, UpdateSourceTrigger=PropertyChanged}" 
         VerticalAlignment="Top" 
         Grid.Column="1" Grid.Row="6" />
<TextBlock HorizontalAlignment="Right" 
           Text="Number:" 
           VerticalAlignment="Top" 
           Grid.Row="7" />
<TextBox Height="23" 
         HorizontalAlignment="Stretch" 
         Text="{Binding Path=SelectedAddress.Number, UpdateSourceTrigger=PropertyChanged}" 
         VerticalAlignment="Top" 
         Grid.Column="1" Grid.Row="7" />        
<TextBlock HorizontalAlignment="Right" 
           Text="City:" 
           VerticalAlignment="Top" 
           Grid.Row="8" />
<TextBox Height="23" 
         HorizontalAlignment="Stretch" 
         Text="{Binding Path=SelectedAddress.City, UpdateSourceTrigger=PropertyChanged}" 
         VerticalAlignment="Top" 
         Grid.Column="1" Grid.Row="8" />
Potenza che già a designtime, visto che per ora le cose sono molto semplici, ci fa capire che siamo sulla strada giusta:
image
A runtime abbiamo la conferma definitiva:
image image
Cambiando la selezione automaticamente il nostro dettaglio si aggiorna, ma non solo, scrivendo qualcosa nel campo “City”, ad esempio, il valore viene riflesso, real-time, anche nella ListView sempre grazie al motore di DataBinding.
Adesso che abbiamo un elemento selezionabile, tracciabile e modificabile non ci resta che renderlo anche cancellabile… ma direi che oggi ho scritto un’altra volta fin troppo :-)
Sorgenti aggiornati: Mvvm.Application-1.2.zip
.m