L'associazione tra controlli dell'interfaccia utente e i dati (contenuti in una Collection, in un documento Xml o in una Datatable
) avviene utilizzando l'oggetto Binding.
Grazie a questo oggetto possiamo specificare il "target", ovvero il destinatario dell'associazione (es. la proprietà Text
di una TextBox
), e la sorgente dei dati (es. la RagioneSociale
di un oggetto di tipo Cliente
).
Possiamo dichiarare l'oggetto Binding direttamente nel markup XAML, assegnando i dati alla proprietà desiderata.
Ecco l'esempio di una TextBox associata ad un campo RagioneSociale
:
<TextBox x:Name="txtRagioneSociale"
Text="{Binding Path=RagioneSociale}" />
Le proprietà più interessanti dell'oggetto Binding
sono:
Proprietà | Descrizione |
---|---|
Path | è un parametro di default e non è obbligatorio specificarlo. Indica il nome della proprietà che contiene il dato nella sorgente dati. L'esempio precedente può essere anche scritto: {Binding RagioneSociale} |
Mode | può assumere due possibili valori OneWay e TwoWay (di default OneWay ).Se vogliamo che le modifiche apportate nel controllo vengano propagate all'oggetto che contiene i dati è necessario specificare TwoWay : {Binding RagioneSociale, Mode=TwoWay} |
Source | è opzionale e consente di specificare la sorgente dati, direttamente nell'oggetto Binding |
Possiamo anche scegliere di gestire l'associazione dati nel code-behind:
Binding b = new Binding(); b.Source = ((Cliente)lbClienti.SelectedItem).RagioneSociale; txtRagioneSociale.SetBinding(TextBox.TextProperty, b);
Associare controlli ed entità
Tipicamente, quando parliamo di Data Layer, intendiamo per "entità" un oggetto che contiene i dati, ad esempio un oggetto di tipo Cliente
contenente una serie di proprietà.
Per associare uno o più controlli a questa entità, possiamo utilizzare la classe DataContext. Essa è esposta dai controlli Silverlight e serve per impostare la sorgente dati. Vediamo come impostarla via codice.
Supponiamo di avere una ListBox
chiamata "lbClienti"
che contiene un elenco di oggetti di tipo Cliente
e una TextBox
chiamata "txtRagioneSociale"
. Ecco come collegare al DataContext
della TextBox
l'oggetto selezionato nella ListBox
:
txtRagioneSociale.DataContext = lbClienti.SelectedItem as Cliente;
L'associazione che abbiamo appena visto è tra un singolo controllo di tipo TextBox
e un singolo oggetto di tipo Cliente
.
Per evitare di dover scrivere una riga di codice per ogni controllo presente nell'applicazione è meglio assegnare l'oggetto di tipo Cliente
ad un Container
che propagherà automaticamente il suo DataContext
a tutti i controlli in esso contenuti.
Ecco l'esempio di un container di tipo StackPanel
il cui DataContext
sarà propagato a tutti i suoi controlli Child
.
Markup
<StackPanel x:Name="spDettagli"> <TextBlock>Ragione Sociale</TextBlock> <TextBox x:Name="txtRagioneSociale" Text="{Binding RagioneSociale, Mode=TwoWay}" /> <TextBlock>Citta</TextBlock> <TextBox x:Name="txtCitta" Text="{Binding Citta, Mode=TwoWay}" /> </StackPanel>
Codice
private void lbClienti_SelectionChanged(object sender, SelectionChangedEventArgs e) { // La ListBox lbClienti contiene un elenco // di oggetti di tipo Cliente spDettagli.DataContext = lbClienti.SelectedItem as Cliente; }
È utile tenere in considerazione anche che la nostra entità (la classe Cliente con i dati), deve implementare l'interfaccia INotifyPropertyChange se vogliamo che possa tenere memorizzate le modifiche apportate ai dati. Questa interfaccia contiene un singolo evento PropertyChange
. Per poterlo utilizzare in una nostra classe il codice da scrivere è abbastanza semplice.
Ecco un esempio di classe Cliente
con due proprietà e che implementa l'interfaccia INotifyPropertyChange
:
class Cliente : INotifyPropertyChanged { private string _ragioneSociale; public string RagioneSociale { get { return _ragioneSociale; } set { _ragioneSociale = value; propertyChange("RagioneSociale"); } } private string _citta; public string Citta { get { return _citta; } set { _citta = value; propertyChange("Citta"); } } private void propertyChange(string _propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(_propertyName)); } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; #endregion }
Collezioni di oggetti ed elenchi
Per collegare una collezione di oggetti ad un controllo in grado di visualizzare un elenco come ad esempio una DataGrid
o una ListBox
è necessario utilizzare una collection che implementi l'interfaccia IEnumerable come ad esempio List
.
Perché le modifiche effettuate dall'utente si propaghino alla nostra collection è necessario che la collection implementi anche l'interfaccia INotifyCollectionChanged. Questa interfaccia consente di gestire gli eventi di modifica, inserimento o eliminazione degli oggetti contenuti nella collection.
Per comodità come collection per i nostri oggetti si può utilizzare la collection generica ObservableCollection
presente nel Framework e che implementa già IEnumerable
e INotifyCollectionChanged
.
In conclusione, i singoli oggetti devono basarsi su una classe che implementi l'interfaccia INotifyPropertyChanged
mentre le collection devono implementare l'interfaccia IEnumerable
e INotifyCollectionChanged
.
In questa seconda parte dell'articolo iniziamo un semplice tutorial: faremo visualizzare in una ListBox un elenco di clienti e i dettagli di ogni cliente selezionato. Inoltre vedremo come implementare la modifica, eliminazione e inserimento dei dati.
L'architettura dell'applicazione prevede da una parte la gestione dei dati e dall'altra l'applicazione Silverlight, ospitata in una pagina HTML, tramite plug-in.
Tra i due estremi troviamo alcuni livelli applicativi necessari a far comunicare il client con il database oltre che utili per organizzare e rendere riusabile l'architettura. L'applicazione Silverlight non può accedere direttamente ai dati se questi sono contenuti lato server, è quindi necessario scrivere uno o più metodi che interagiscono con la base dati ed esporre questi metodi attraverso un Web Service.
Per l'accesso ai dati ci serviamo di LinQ to Sql, che ci consente di realizzare con poco sforzo la gestione di un database SqlServer. Se volessimo utilizzare un database diverso da SqlServer ci potremmo servire di LinQ to Entity.
Per il nostro esempio utilizziamo Visual Web Developer Express 2008, creiamo un nuovo progetto Silverlight utilizzando il template che prevede la creazione di una applicazione Web e di un progetto silverlight separati.
Nota: Se non troviamo il template, probabilmente non abbiamo ancora scaricato i Silverlight Tools per Visual Studio.
I prossimi passi saranno:
- Creazione del database e della tabella Cliente
- Impostare la logica di accesso ai dati con LinQ to Sql
- Realizzare un Web Service che si interfacci con i dati
- Creare il layout dell'applicazione
- Il Databind: associare i controlli con i dati e gestire le operazioni CRUD
Creare il database
Aggiungiamo al progetto Web un nuovo DB SqlServer Express cliccando con il tasto destro sul progetto SilverlightApplication.Web e cliccando su Aggiungi > Nuovo elemento
.
Scegliamo Database SQL
e chiamiamo il nuovo database "NegozioDB.mdf"
Rispondiamo "Si" per spostare il file nella cartella AppData
.
Una volta creato il database dobbiamo creare la tabella Clienti
. Da Esplora Database
(linguetta vicina a "Esplora Soluzioni" o Visualizza > Esplora Database
) espandiamo la voce NegozioDB
, clicchiamo con il tasto destro sulla cartella Tabelle
e selezioniamo la voce Aggiungi nuova tabella
.
Aggiungiamo le seguenti colonne:
Nome colonna | Tipo di dati | Ammetti Null |
---|---|---|
IDCliente | int | no |
RagioneSociale | nvarchar(150) | no |
Citta | nvarchar(50) | no |
Attivo | bit | no |
Impostiamo la colonna "IDCliente" come Primary Key
Perché questa chiave sia generata automaticamente dal sistema, impostiamo la proprietà Identità
(IsIdentity) a Sì
. Salviamo la tabella con il nome "Cliente".
Ora aggiungiamo qualche record alla tabella. Clicchiamo con il tasto destro su Client
, in Esplora Database
e selezioniamo Mostra dati tabella
.
Accesso ai dati con LinQ to Sql
Come abbiamo detto, il database risiede fisicamente sul server mentre l'applicazione Silverlight è eseguita sul client.
Per trasferire i dati dal database all'applicazione Silverlight utilizziamo delle entità. Una entità è rappresentata da una classe che contiene i dati prelevati dal database, ne memorizza i campi, e li espone sotto forma di proprietà. L'entità non contiene logica di accesso al database e svolge una funzione di trasporto.
Per gestire i dati come oggetti e garantirne la persistenza sul database esistono da tempo dei progetti detti ORM, tra cui il notissimo NHibernate.
Dalla versione 3.5 del .NET Framework sono stati inseriti una serie di nuove funzionalità partendo da LinQ fino ad arrivare ad un vero e proprio ORM chiamato LinQ to Entity. In questo articolo utilizzeremo LinQ to Sql per creare un modello a oggetti e un motore di persistenza con pochi click.
Per creare il modello a oggetti possiamo utilizzare l'apposito designer: aggiungiamo un elemento al progetto SilverlightApplication.Web
, selezioniamo il template Classi LinQ to Sql
e diamogli il nome NegozioClasses.dbml
.
Ora, visualizziamo la finestra del Database Explorer e trasciniamo la tabella sul designer di LinQ to Sql.
Questa entità dovrà trasportare i dati in entrambi i sensi tra server e client, perciò dobbiamo renderla serializzabile. Clicchiamo su una zona libera del designer e cambiamo la proprietà Serialization Mode
in Unidirectional
.
Il nostro un modello a oggetti e il relativo motore di persistenza sono pronti. Nel prosieguo del tutorial vedremo come utilizzare la classe Cliente
e la classe DataContext
(NegozioDBClasseDataContext
per la precisione).
Iniziamo questa terza parte dell'articolo creando il servizio Web che espone metodi per leggere e scrivere dati.
Creare il Web Service
Un Web Service è simile ad un normale metodo. La sua utilità è il fatto che è richiamabile attraverso internet perché si basa sui protocolli standard (es. http, soap, xml). I Web Service servono per far parlare tra loro le applicazioni e tipicamente non vengono usati in modo diretto dall'utente.
Ai fini del nostro tutorial, creiamo un Web Service dentro l'applicazione Web, che esporrà alla nostra applicazione Silverlight i metodi per leggere e scrivere nel database: GetClienti
, SaveCliente
, DeleteCliente
.
Clicchiamo con il tasto destro sulla applicazione Web (SilverlightApplication.Web
), aggiungiamo un nuovo elemento Servizio WCF Abilitato per Silverlight
e chiamiamo il Web Service NegozioService.svc
All'interno della classe NegozioService
, dichiariamo una variabile db
di tipo NegozioClassesDataContext
e inizializziamola nel costruttore della classe
public class NegozioService { NegozioClassesDataContext db; public NegozioService() { db = new NegozioClassesDataContext(); } }
Questa variabile rappresenta il nostro motore di persistenza creato automaticamente da LinQ to Sql e ci sarà utile per gestire il database.
Il primo metodo che scriviamo è GetClienti() che avrà come risultato una collection di oggetti di tipo cliente: List<Cliente>
. Sostituite il codice del metodo DoWork
con il seguente frammento di codice
[OperationContract] public List<Cliente> GetClienti() { return db.Clientes.ToList(); }
L'entità Cliente
che stiamo utilizzando è stata creata automaticamente quando abbiamo creato il modello a oggetti con LinQ to Sql nello step precedente.
All'interno del metodo SaveCliente dobbiamo capire se si tratta di una nuova entità oppure se si tratta di modificarne una esistente e per fare questo utilizziamo il valore presente nella proprietà IDCliente
. Se è inferiore a 1 è una entità che dobbiamo inserire altrimenti modificare. Queste operazioni le eseguiamo servendoci del DataContext creato da LinQ to Sql.
Aggiungiamo ora il metodo SaveCliente
che accetta come parametro una entità di tipo Cliente
[OperationContract] public Cliente SaveCliente(Cliente _entity) { if (_entity == null) { throw new NullReferenceException("Cliente is null"); } if (_entity.IDCliente < 1) { // Insert db.Clientes.InsertOnSubmit(_entity); } else { // Update Cliente original = (from c in db.Clientes where c.IDCliente == _entity.IDCliente select c).Single(); if (original == null) { throw new ArgumentException("Cliente not found"); } original.RagioneSociale = _entity.RagioneSociale; original.Citta = _entity.Citta; original.Attivo = _entity.Attivo; } db.SubmitChanges(); return _entity; }
Come si può vedere, per rendere persistenti le operazioni di modifica dei dati è necessario chiamare il metodo SubmitChanges
sul DataContext
. La funzione ritorna l'entità inserita o modificata per dare la possibilità al client di modificare i dati in memoria.
Per eliminare una entità, prima controlliamo che esista utilizzando una query LinQ. Se esiste procediamo alla sua eliminazione chiamando il metodo DeleteOnSubmit
a cui passeremo l'entità da eliminare. Scriviamo il metodo DeleteOnSubmit
che ritorna l'entità eliminata per consentire al client di modificare i suoi dati in memoria:
[OperationContract] public Cliente DeleteCliente(Cliente _entity) { var query = (from c in db.Clientes where c.IDCliente == _entity.IDCliente select c).SingleOrDefault(); if (query != null) { db.Clientes.DeleteOnSubmit(query); db.SubmitChanges(); return query; } else { throw new ArgumentException("Cliente not found"); } }
Creare il layout
In questo step aggiungiamo i controlli necessari per visualizzare l'elenco dei clienti e il dettaglio di ogni cliente selezionato. Inseriamo anche i pulsanti necessari per effettuare le operazioni di modifica sui dati.
Non ci soffermiamo troppo sulla creazione del layout di una applicazione Silverlight, cerchiamo qui di creare il minimo indispensabile al funzionamento dell'applicazione.
Dal progetto SilverlightApplication
, apriamo il file Page.xaml
. La pagina contiene una Grid
, che è l'elemento di default creato quando si crea una nuova pagina. Aggiungiamo due colonne alla Grid
in modo da mettere a sinistra la ListBox
e a destra i controlli per visualizzare i dettagli.
Per separare le due parti, aggiungiamo un controllo GridSplitter
. Questo controllo lo aggiungiamo prendendolo dalla toolbox, in modo da farci aggiungere automaticamente il namespace necessario per il suo utilizzo.
Per inserire la barra nel punto giusto, posizioniamo il cursore subito dopo la definizione delle colonne e facciamo doppio click sul controllo GridSplitter
presente nella toolbox. Per evidenziare meglio la divisione, aggiungiamo un valore (es. "Gainsboro") alla proprietà Background
.
Aggiungiamo ora una ListBox
inserendo il seguente codice XAML
<ListBox x:Name="lbClienti" Grid.Column="0" Margin="15" />
Impostando l'attributo Grid.Column="0"
della ListBox facciamo in modo che venga visualizzata nella prima colonna a sinistra dello splitter.
Ora aggiungiamo i controlli per visualizzare i dettagli. Utilizzeremo come container dei controlli uno StackPanel
. Utilizziamo come label dei controlli di tipo TextBlock
, per visualizzare i dati delle TextBox
e un CheckBox
, per le operazioni di modifica dei normali Button
. Aggiungiamo quindi il seguente codice Xaml subito dopo il controllo ListBox
lbClienti
<StackPanel x:Name="spDettagli" Grid.Column="1" Margin="15"> <TextBlock>Ragione Sociale</TextBlock><TextBox x:Name="txtRagioneSociale" /> <TextBlock>Citta</TextBlock><TextBox x:Name="txtCitta" /> <TextBlock>Attivo</TextBlock><CheckBox x:Name="chkAttivo" /> <Button x:Name="btnSalva" Content="Salva" Margin="2" /> <Button x:Name="btnNuovo" Content="Nuovo" Margin="2" /> <Button x:Name="btnElimina" Content="Elimina" Margin="2" /> </StackPanel>
Il Databind: associare i controlli con i dati
Siamo arrivati finalmente al collegamento tra i controlli che sono nell'applicazione Silverlight e i dati restituiti dal Web Service. Per collegare la SilverlightApplication
al nostro NegozioService
, dobbiamo aggiungere una Riferimento al servizio nel progetto.
Clicchiamo con il tasto destro sulla cartella Riferimenti
presente nel progetto SilverlightApplication
e selezioniamo "Aggiungi riferimento al servizio".
Nella finestra che appare possiamo individuare il servizio. È facile farlo quando il Web Service è presente nella stessa solution perchè abbiamo a disposizione il pulsante Individua
che, se selezionato, ci mostra i servizi presenti negli altri progetti.
Selezioniamo il servizio visualizzato e diamogli il nome NegozioServiceReference
.
Dopo aver confermato con Ok
, viene creata una classe proxy che ci permette di interrogare il Web Service come se fosse un oggetto locale.
Torniamo al file Page.xaml
e premiamo F7
per visualizzare la pagina di codice (code behind).
Qui dichiariamo di voler utilizzare il servizio attraverso la classe proxy. Inseriamo quindi una clausola using
:
using SilverlightApplication.NegozioServiceReference;
All'interno della classe Page, dichiariamo una variabile di tipo ObservableCollection
chiamata elencoClienti
. Questa variabile ci sarà utile per memorizzare l'elenco di tutti i clienti ed essendo di tipo ObservableCollection
notificherà automaticamente ai controlli Silverlight tutti gli eventi di modifica degli elementi che contiene.
System.Collections.ObjectModel.ObservableCollection<Cliente> elencoClienti;
Dichiariamo ora una variabile di tipo NegozioServiceClient
(il proxy creato automaticamente) e chiamiamola serviceClient
. Questa variabile è dichiarata ma non ancora inizializzata. Potremmo farlo nel costruttore, ma esiste un evento che viene sempre scatenato nella pagina Silverlight al termine del caricamento iniziale, impariamo ad utilizzarlo e inizializziamo il proxy nel metodo gestore dell'evento.
Nota: Visual Studio ci aiuta a scrivere i gestori di evento, basta premere consecutivamente per due volte il tasto Tab
dopo aver digitato l'operatore +=
public partial class Page : UserControl { NegozioServiceClient serviceClient; ObservableCollectionelencoClienti; public Page() { InitializeComponent(); Loaded += new RoutedEventHandler(Page_Loaded); } }
e nel metodo Page_Loaded
possiamo procedere a inizializzare il nostro oggetto serviceClient
.
void Page_Loaded(object sender, RoutedEventArgs e) { serviceClient = new NegozioServiceClient(); }
Ora l'oggetto serviceClient
è in grado di richiamare il Web Service e farci restituire l'elenco dei clienti. Dobbiamo quindi ricevere la collection con questo elenco di entità di tipo Cliente
e associarla alla ListBox
.
Quello che faccaimo ora è assegnare un gestore di evento da richiamare al termine del caricamento dell'elenco dei clienti. Poi lanciamo la chiamata vera e propria.
void Page_Loaded(object sender, RoutedEventArgs e) { serviceClient = new NegozioServiceClient(); serviceClient.GetClientiCompleted += new EventHandler<GetClientiCompletedEventArgs>(serviceClient_GetClientiCompleted); serviceClient.GetClientiAsync(); }
Questo pattern asincrono è reso abbastanza semplice perchè per ogni metodo presente nel proxy contiene sia l'evento XXXCompleted
a cui registrare un gestore e sia il metodo XXXAsync()
che serve per far partire la chiamata al servizio.
Infine la collection con l'elenco dei Clienti
sarà ritornata nel metodo serviceClient_GetClientiCompleted
, che gestisce l'evento del caricamento completato. È qui che possiamo stabilire il collegamento tra la collection e il controllo ListBox
.
void serviceClient_GetClientiCompleted(object sender, GetClientiCompletedEventArgs e) { elencoClienti = e.Result; lbClienti.ItemsSource = elencoClienti; }
Controlli come ListBox
o DataGrid
hanno lo scopo di visualizzare un elenco di informazioni che possono essere contenute in una collection di elementi, come nel nostro tutorial, oppure in un documento XML o in una Datatable
di ADO.NET. Questi controlli espongono la proprietà ItemsSource
a cui collegare direttamente la fonte dati.
Ora dobbiamo indicare la proprietà RagioneSociale
presente nella classe Cliente
come il membro da visualizzare nella ListBox
utilizzando la proprietà DisplayMemberPath
. Spostiamoci nel file Page.xaml
e modifichiamo il tag della ListBox
lbClienti
in questo modo
<ListBox x:Name="lbClienti" Grid.Column="0" Margin="15"
DisplayMemberPath="RagioneSociale" />
Lanciamo l'applicazione premendo il pulsante F5
e vediamo all'opera quanto fatto. Premiamo Ok
se viene richiesta la modifica del web.config
.
La prima esecuzione può risultare lenta ma dopo qualche secondo vedremo apparire l'elenco dei clienti nella ListBox.
Ora dobbiamo associare ai controlli presenti nello StackPanel
i dati contenuti nel cliente selezionato con la ListBox
lbClienti
. Per farlo, dobbiamo dichiarare nel codice XAML il nome del gestore che si occuperà dell'evento SelectionChanged
della ListBox
.
<ListBox x:Name="lbClienti" Grid.Column="0" Margin="15"
DisplayMemberPath="RagioneSociale"
SelectionChanged="lbClienti_SelectionChanged" />
Quando scriviamo direttamente il codice XAML, l'intellisense di Visual Studio ci aiuta. Nel caso della definizione degli eventi e dell'associazione tra un evento e un gestore evento, ci permette di creare velocemente il metodo confermando i suggerimenti automatici.
Nel metodo lbClienti_SelectionChanged
che abbiamo appena creato dobbiamo associare l'elemento selezionato nella ListBox
alla proprietà DataContext
dello StackPanel
.
Certo, avremmo potuto associarlo ad ogni singolo controllo dentro lo StackPanel
ma è molto più semplice associarlo ad un Container sapendo che così la proprietà verrà propagata automaticamente ai controlli in esso contenuti. Spostiamoci nella pagina del codice ed aggiungiamo:
private void lbClienti_SelectionChanged(object sender, SelectionChangedEventArgs e) { spDettagli.DataContext = lbClienti.SelectedItem; }
L'elemento selezionato nella ListBox
viene associato alla proprietà DataContext
dello StackPanel
e quindi automaticamente propagato al DataContext
di tutti i controlli.
Ogni elemento nella ListBox corrisponde ad un oggetto di tipo Cliente
, la classe Cliente
contiene proprietà come RagioneSociale
, Citta
, Attivo
. Per stabilire che la proprietà Text
della txtRagioneSociale
deve visualizzare la proprietà RagioneSociale
dell'oggetto Cliente
selezionato utilizziamo finalmente il Binding!
<TextBox x:Name="txtRagioneSociale" Text="{Binding RagioneSociale}" />
La proprietà Text
(detta proprietà "target"), contiene il collegamento alla sua fonte dati che in questo caso è il nome di una proprietà dell'oggetto impostato nel DataContext
. Procediamo allo stesso modo con il resto dei controlli prestando attenzione al controllo CheckBox
la cui proprietà target è IsChecked
.
<TextBox x:Name="txtRagioneSociale" Text="{Binding RagioneSociale}" /> ... <TextBox x:Name="txtCitta" Text="{Binding Citta}" /> ... <CheckBox x:Name="chkAttivo" IsChecked="{Binding Attivo}" />
Eseguiamo l'applicazione e verifichiamo che la selezione di un elemento sulla ListBox
provochi l'associazione con i controlli nello StackPanel
.
Proviamo a modificare il testo di uno dei clienti selezionati. Cambiando selezione e ritornando su di esso vediamo che le modifiche vanno perse. Per mantenere negli oggetti associati le modifiche fatte attraverso i controlli dobbiamo cambiare valore all'attributo Mode
del Binding
inserendo il valore TwoWay
.
<TextBox x:Name="txtRagioneSociale" Text="{Binding RagioneSociale, Mode=TwoWay}" />
Se ora riproviamo ad eseguire l'applicazione e a cambiare i dati, i cambiamenti non solo vengono mantenuti ma si propagano anche alla collection collegata con la ListBox
.
Questo perché la classe Cliente
, che è stata creata automaticamente da LinQ to Sql, implementa l'interfacci INotifyPropertyChanged
. Inoltre anche la collection di oggetti di tipo Cliente
, che viene restituita dal Web Service, è di tipo System.Collections.ObjectModel.ObservableCollection
, quindi è in grado di gestire le modifiche agli elementi contenuti notificandole ai controlli.
Aggiungiamo i gestori di evento ai pulsanti
e iniziamo a definire il comportamento del bottone Nuovo
:
private void btnNuovo_Click(object sender, RoutedEventArgs e) { Cliente nuovo = new Cliente(); nuovo.RagioneSociale = "Inserisci dati"; nuovo.Citta = string.Empty; spDettagli.DataContext = nuovo; }
Dopo aver creato una nuova istanza di Cliente
, valorizzata con dati di default, associamo l'oggetto appena creato, e non ancora contenuto nel database, alla proprietà DataContext
dello StackPanel
. In questo modo indipendentemente da quello che è stato prima selezionato nella ListBox
, i dati nei controlli contenuti nello StackPanel
cambiano e vengono collegati al nuovo oggetto.
Ora implementiamo il codice del metodo btnSalva_Click
. Qui dobbiamo chiamare in maniera asicrona il metodo SalvaClienteAsync
presente nel Web Service
. A questo metodo dobbiamo passare l'oggetto correntemente associato al DataContext
dello StackPanel
e possiamo registrarci per ricevere il segnale della fine dell'operazione lato server in modo da modificare l'elenco dei clienti che teniamo memorizzato nella variabile elencoClienti
.
private void btnSalva_Click(object sender, RoutedEventArgs e) { serviceClient.SaveClienteCompleted += new EventHandler<SaveClienteCompletedEventArgs>(serviceClient_SaveClienteCompleted); serviceClient.SaveClienteAsync(spDettagli.DataContext as Cliente); } void serviceClient_SaveClienteCompleted(object sender, SaveClienteCompletedEventArgs e) { if (e.Error != null) { // C'è stato un errore visualizziamo il messaggio MessageBox.Show(e.Error.Message); } else { // Se si tratta di un nuovo elemento aggiungiamolo all'elenco if (elencoClienti.FirstOrDefault(c => c.IDCliente == e.Result.IDCliente) == null) { elencoClienti.Add(e.Result); } } }
Ora implementiamo il metodo btnElimina_Click
in maniera simile
private void btnElimina_Click(object sender, RoutedEventArgs e) { serviceClient.DeleteClienteCompleted += new EventHandler(serviceClient_DeleteClienteCompleted); serviceClient.DeleteClienteAsync(spDettagli.DataContext as Cliente); } void serviceClient_DeleteClienteCompleted(object sender, DeleteClienteCompletedEventArgs e) { if (e.Error != null) MessageBox.Show(e.Error.Message); else { // Cancelliamo il datacontext dello StackPanel e rimuoviamo l'elemento dall'elenco spDettagli.DataContext = null; elencoClienti.Remove(elencoClienti.FirstOrDefault(c => c.IDCliente == e.Result.IDCliente)); } }