Windows Forms Databinding

Slides:



Advertisements
Presentazioni simili
DBMS (DataBase Management System)
Advertisements

Recupero debito quarto anno Secondo incontro
Informatica Recupero debito quarto anno Terzo incontro.
Capitolo 8 Array Lucidi relativi al volume: Java – Guida alla programmazione James Cohoon, Jack Davidson Copyright © The McGraw-Hill Companies srl.
Type Checking (1° parte)
Differenze nei vari linguaggi di Elisa Trifirò e Barbara Tacchino
1 Astrazioni sui dati : Specifica ed Implementazione di Tipi di Dato Astratti in Java.
Classi ed Oggetti in Java (Cenni). Richiami Ruolo delle Classi in Java Oggetti.
Liste di Interi Esercitazione. Liste Concatenate Tipo di dato utile per memorizzare sequenze di elementi di dimensioni variabile Definizione tipicamente.
MultiSet, Liste Ordinate
Le gerarchie di tipi.
Metodologie di Programmazione = decomposizione basata su astrazioni
1 Le gerarchie di tipi: implementazioni multiple e principio di sostituzione.
Liste Ordinate 3 Maggio Ultima Lezione Abbiamo visto i tipi di dato astratti IntList e StringList Realizzano liste di interi e di stringhe Realizzati.
LIP: 1 Marzo 2005 Classe Object e Vettori. Partiamo da Lesercizio dellultima esercitazione realizzato tramite array Vedremo come si puo fare in modo piu.
Università degli Studi di Modena e Reggio Emilia
Biglietti e Ritardi: schema E/R
Argomenti dalla linea dei comandi Gli argomenti possono essere passati a qualsiasi funzione di un programma, compresa la main(), direttamente dalla linea.
1 Programmazione ad oggetti in Java E.Mumolo, DEEI
La Riflessione computazione Elisa Ferrando. Cos è la Riflessione La Riflessione Sistema riflessivo Sistema computazionale.
Approfondimento delle classi
Corso di Laurea in Ingegneria per lAmbiente e il Territorio Informatica per lAmbiente e il Territorio Docente: Giandomenico Spezzano Tutor: Alfredo Cuzzocrea.
Sistemi Operativi GESTIONE DEI PROCESSI.
Java Collections.
FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return * sin(0.75); } float f1(int x) { return.
DBMS ( Database Management System)
Gestione sito Dario Zucchini 29/02/2012.
1 Programmazione = decomposizione basata su astrazioni (con riferimento a Java)
1 – Costruzione dell’alberatura
Lezione 12 Riccardo Sama' Copyright Riccardo Sama' Excel.
Visual Basic e accesso ai DATABASE
Costruire pagine per il WEB
1 Astrazioni sui dati : Ragionare sui Tipi di Dato Astratti dispense prof. G. Levi.
ISTITUTO STATALE DI ISTRUZIONE SUPERIORE F. ENRIQUES CORSO JAVA – PROVA FINALE DEL 21 MAGGIO 2007 NOME: COGNOME: ________________________________________________________________________________.
Costruire una tabella pivot che riepiloghi il totale del fatturato di ogni agente per categorie di vendita, mese per mese. Per inserire una tabella pivot.
1 cin>>c8 s.r.l A.A Generalità Uno dei concetti largamente adottati negli ultimi anni dai professionisti del software in fase di sviluppo.
Microsoft Access (parte 5) Introduzione alle basi di dati Scienze e tecniche psicologiche dello sviluppo e dell'educazione, laurea magistrale Anno accademico:
Percorso didattico per l’apprendimento di Microsoft Access Modulo 5
INTRODUZIONE A JAVASCRIPT
Percorso didattico per l’apprendimento di Microsoft Access Modulo 5
CORSO Di WEB DESIGN prof. Leonardo Moriello
Microsoft Access Maschere (II).
Fondamenti di informatica Oggetti e Java Luca Cabibbo Luca Cabibbo – Fondamenti di informatica: Oggetti e Java Copyright © 2004 – The McGraw-Hill Companies.
Diagramma delle Classi
Esercitazione su Vector. Permette di definire collezioni di dati generiche, che sono in grado di memorizzare elementi di ogni sottotipo di Object Definito.
IV D Mercurio DB Lezione 2
MySQL Database Management System
Microsoft Access Chiavi, struttura delle tabelle.
Liste Concatenate 11 Aprile E’ una delle strutture dati fondamentali in tutti i linguaggi di programmazione di alto livello Una Lista Concatenata.
Data Base ACCESS EM 09.
1 Astrazioni sui dati : Ragionare sui Tipi di Dato Astratti.
LIP: 2 Maggio 2008 Classi Astratte. Cos’e’ una Classe Astratta una classe astratta e’ un particolare tipo di classe permette di fornire una implementazione.
Sommario Oggetti immutabili e non Tipi Primitivi: String, Arrays.
Progettare una classe 21 Febbraio La classe BankAccount Vogliamo realizzare una classe i cui oggetti sono dei semplici conti bancari. * Identifichiamo.
1 Metodologie di Programmazione = decomposizione basata su astrazioni.
LIP: 11 Maggio 2007 Classi Astratte. Cos’e’ una Classe Astratta una classe astratta e’ un particolare tipo di classe permette di fornire una implementazione.
Esercitazione 14 Marzo Esercizio dell’altra volta Definire un tipo di dato Abbonato i cui oggetti descrivono le informazioni relative ad un abbonato.
LIP: 4 Maggio 2007 Interfacce. Cos’e’ una Interfaccia una interfaccia e’ un particolare tipo di classe contiene solo la specifica non ha implementazione.
Microsoft Access (parte 3) Introduzione alle basi di dati Scienze e tecniche psicologiche dello sviluppo e dell'educazione, laurea magistrale Anno accademico:
Cloud Tecno V. Percorso didattico per l’apprendimento di Microsoft Access 4 - Le maschere.
Microsoft Access Filtri, query. Filtri Un filtro è una funzione che provoca la visualizzazione dei soli record contenenti dati che rispondono a un certo.
XVRC2 Emanuele Ruffaldi Giugno Tre esperimenti con S3D ► Estensioni del Linguaggio ► Pre-Compilatore ► Esecuzione dentro il Java L C J.
Access Breve introduzione. Componenti E’ possibile utilizzare Access per gestire tutte le informazioni in un unico file. In un file di database di Access.
+ Geolocalizzazione Nicolò Sordoni. + Servizi di localizzazione In Windows Phone, la posizione dell’utente può essere rilevata in 3 differenti modi: GPS:
SQLite. Introduzione a SQLite Oltre alla possibilità di memorizzare informazioni persistenti attraverso Preferences e files, Android mette a disposizione.
Gestire la navigazione. Creare un’app multi Controller La quasi totalità delle app è suddivisa in più ViewControllers, ognuno con specifiche funzionalità.
Controlli. Storyboard L’assistant editor consente una visualizzazione contestuale in cui sono affiancati verticalmente il ViewController nello storyboard.
Transcript della presentazione:

Windows Forms Databinding Raffaele Rialdi MVP C# malta@vevy.com http://mvp.support.microsoft.com

Cos'è il binding? Letteralmente significa legame e permette di stabilire automaticamente lo scambio di valori tra controllo e una sorgente dati. Il databinding evita codice noioso e ripetitivo nel quale assegnamo i dati al controllo e successivamente li riassegnamo alla sorgente dati. Il binding con DataSource 'poveri' implica l'uso di reflection e quindi impoverisce le performance. Se invece il DataSource implementa le interfacce giuste il discorso è molto diverso.

Big picture ... In ADO.NET le sorgenti dati disconnesse non hanno più il concetto di record corrente. Il binding di dotnet è gestito da un intermediario tra controllo e sorgente dati La presenza di un unico intermediario per bindare più controlli garantisce il sync tra questi Sync Data BindingManagerBase

Sincronizzazione tra controlli E se non volessimo i due controlli sincronizzati? E se volessimo scorrere i dati indipendentemente sui due controlli? Risposta: bisogna avere due intermediari BindingManagerBase Sync Data BindingManagerBase

BindingContext BindingContext è semplicemente una lista di BindingManagerBase mantenuta tramite Hashtable Poiché il nome del datasource è parte della chiave della Hashtable, non più di un BindingManagerBase con lo stesso datasource può esistere in un BindingContext Perció per non avere sync tra due controlli, i due BindingManagerBase devono appartenere a due BindingContext diversi BindingContext (Hashtable) BindingManagerBase Sync Data BindingManagerBase BindingContext (Hashtable)

Esempio SimpleBinding Text, Font, BindingContext

Binding Manager Il binding manager è l'intermediario Per ogni datasource esiste un solo binding manager Per ogni binding manager ci sono uno o più controlli Questo serve per avere più controlli sincronizzati durante la navigazione dei dati. La classe base del binding manager è BindingManagerBase (astratta) e ha due classi derivate: PropertyManager gestisce il binding con singoli elementi CurrencyManager gestisce il binding con liste di elementi

se è null viene usato ToString() Simple binding Associa un qualsiasi tipo ad un controllo in modo da semplificare la presentazione di un valore e poterlo aggiornare Il binding con un singolo elemento implica l'uso di PropertyManager La proprietà Position sarà sempre 0 Il binding con una lista di elementi implica l'uso di CurrencyManager che ha il concetto di 'record corrente'. Si usa Position per navigare le righe mostrate Non si usa Position per leggere la posizione perchè la lista potrebbe contenere elementi che non vengono mostrati (es. filtro sulla dataview) Si usa Current per leggere l'elemento nella lista sottostante (datasource) Proprietà controllo DataMember DataSource int i=5; myLabel.DataBindings.Add("Text", i, null); se è null viene usato ToString()

Tip FAQ! Ricavare l'elemento del datasource data la riga selezionata nella datagrid. In caso di DataSet/DataTable ritorna una DataRowView DataRowView drv = GetCurrentBindedObject(DataGrid1) as DataRowView; private object GetCurrentBindedObject(DataGrid dg) { if(dg == null || dg.DataSource == null) return null; BindingManagerBase bmb = dg.BindingContext[dg.DataSource]; if(bmb == null || bmb.Count == 0) return null; return bmb.Current; }

Sincronia dei dati Le variazioni del controllo vengono messe nel datasource quando: Il datasource è un oggetto che espone proprietà Il datamember è specificato esplicitamente nel binding Le variazioni del datasource vengono messe nel controllo quando: Sono vere le condizioni di prima Esiste un evento [NomeProprietà]Changed (ValChanged) che segnala le modifiche al datasource oppure La classe supporta IBindingList (lo vedremo più avanti)

Simple e Complex Binding CurrencyManager oppure PropertyManager BindingContext BindingManagerBase BindingManagerBase DataSource Data Simple Binding DataMember Bindings BindingsCollection oppure ControlBindingsCollection Binding Control Binding PropertyName Binding BindingContext Complex Binding BindingManagerBase IBindingList, ITypedList, ... Data DataSource Simple Binding DataMember Binding Control PropertyName

Esempio SingleElement Simple binding sul singolo elemento

Simple Binding: format e parse La classe binding (disponibile solo nel simple binding) offre due eventi importanti: format. Intercetta il dato proveniente dal DataSource prima che venga impostato nel controllo. parse. Intercetta il dato che dal controllo sta per essere trasferito al DataSource È un ottimo metodo per migliorare la qualità della visualizzazione dei dati Non è utile alla validazione che deve essere effettuata dal controllo

Esempio FormatParse eventi format e parse

Complex binding usando gli oggetti ado.net IListSource permette di 'scoprire' qual'è la collection (IList) che contiene i veri elementi con cui effettuare il binding. La collection è la DataView Gli elementi sono le DataRowView DataSource DataMember DataSet IList IListSource.GetList() { return this.DefaultView; } DataTable DataView DataRow DataRowView DataRow DataRowView DataRow DataRowView

Tips Cosa specificare in DataSource e DataMember? DataSource = myDataSet DataMember = myTable.myColumn Non specificare mai nel DataSource myDataSet.myTable perché: il nome del DataSource funge da Key in BindingContext il designer usa la convenzione in alto Quando si usa il CurrencyManager, può essere necessario usare il suo metodo Refresh affinché il controllo venga aggiornato. La Listbox ha bisogno di questo refresh mentre altri controlli no. Affinché il DataSource sia sicuramente aggiornato è necessario chiamare EndCurrentEdit

Perché rinunciare al dataset Non sempre abbiamo bisogno di tutto ciò che il dataset offre Il dataset è un contenitore generico e come tale è costretto a gestire in modo meno efficente i dati al suo interno Anche quando viene tipizzato l'uso a design time è farraginoso perchè ci sono troppe proprietà/metodi Ma soprattutto perchè non rappresenta esattamente i nostri dati ma siamo costretti ad adeguare i dati al dataset

Custom entities Creare una collection dei nostri dati Possibilmente tipizzarla Implementare almeno: IEnumerable per il mondo web IList per il mondo WinForms Molte altre interfacce per renderla ricca di funzionalità al runtime e al design time (... le vedremo ...) CustomerCollection Customer

 Collection Strada più veloce: derivare da ArrayList e implementare gli overload tipizzati per rendere più piacevole l'uso della collection Strada più elegante: implementare IList, ICollection e IEnumerable usando per composition un ArrayList privato Derivando CollectionBase non otteniamo una collection ben tipizzata e ci 'brucia' la possibilità di derivare la collection da un'altra classe base visto che in dotnet non c'è multiple inheritance

 Collection Implementare IList (e quindi anche ICollection e IEnumerable) IList: metodi base come Add, Remove, Clear e Contains IList è l'unica interfaccia indispensabile per essere un datasource valido nelle Winform ICollection: proprietà Count, SyncRoot IEnumerable: GetEnumerator indispensabile per poter usare foreach IEnumerable è l'unica interfaccia indispensabile per essere un datasource valido nelle Webform

 Duplicabilità (opzionale) ICloneable. Unico metodo è Clone MSDN dice che è facoltà del programmatore scegliere se si vuole implementare Clone come: Deep Copy: copia della collection e di tutti gli elementi referenziati [Implementazione complessa] Shallow Copy: copia della sola collection che condividerà gli elementi con la collection di partenza [Implementazione semplice]

 Usabile dal designer IComponent oppure MarshalByValueComponent IComponent unito agli attributi permette l'uso nel designer. Si aggiunge la collection alla toolbox e si trascina sulla superficie del form [DesignerCategory("")] oppure [DesignerCategory("component")] [ToolboxItem(true)] [DesignTimeVisible(true)] MarshalByValueComponent ci risparmia la fatica di implementare IComponent ma ci "brucia" la possibilità di derivare da un'altra classe

 IListSource: gerarchia a design time Dato un DataSource vedo in DataMember l'elenco delle collection figlie Una possibilità è quella di usare un oggetto contenitore e segnare il getter delle collection con l'attributo: DesignerSerializationVisibility Se invece si vuole la gerarchia analoga a quella del DataSet devo costruire un oggetto analogo al DataViewManager: il count riporta sempre 1 (così a design time c'è una sola riga) ITypedList riporta le informazioni sulle inner-collection costruire un PropertyDescriptor personalizzato Implementazione omessa nell'esempio per brevità

 Serializzabile, usabile da remoting [Serializable] oppure ISerializable La serializzazione permette di attraversare i remoting boundary

 Abilitazione alle notifiche, alle ricerche, editabile e ordinabile IBindingList fornisce tutte quelle caratteristiche che troviamo nella DataView. È l'interfaccia più noiosa da implementare Proprietà Allowxxx, Supportxxx, Sortxxx Metodo AddNew che permette di inserire Metodo ApplySort che permette di ordinare Evento ListChanged per segnalare al controllo che i dati nella lista sono cambiati Questo implica che l'oggetto child (collezionato) deve segnalare alla lista se e quando è cambiato

 Abilitazione alle notifiche, alle ricerche, editabile e ordinabile E se non si implmenta IBindingList? Per aggiornare i dati è necessario dare uno 'scrollone' al binding: Per notificare le modifiche è necessario creare un evento che abbia il nome della proprietà + "Changed" Esattamente quanto già visto in una slide iniziale e nell'esempio "SingleElement" private void RefreshGrid() { BindingManagerBase bmb = dataGrid1.BindingContext[dataGrid1.DataSource]; bmb.SuspendBinding(); bmb.ResumeBinding(); } Tip!

 Informazioni sullo schema ITypedList permette ai controlli di scoprire lo schema a runtime. Permette di conoscere il tipo che si 'nasconde' dietro una proprietà. Metodo GetItemProperties. Se la proprietà è un tipo complesso (collection) bisogna fornirgli l'elenco delle proprietà del tipo che si nasconde dietro la collection. Metodo GetListName. Se la proprietà è una collection, noi dovremo fornirgli il nome (stringa) del tipo collezionato

 Informazioni sullo schema Con ITypedList possiamo fare a meno delle TableStyles: cambiare nomi alle colonne (per esempio "NomeAzienda" in "Nome Azienda") ordinare le colonne in modo arbitrario nascondere le colonne non desiderate public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors) { // prende il nome dell'oggetto collezionato con una funzione custom Type t = GetPropertyType(listAccessors); // vedi esempio per l'implementazione PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(t); // dentro pdc ci sono tutte le informazioni sul tipo, compresi gli attributi pdc = pdc.Sort(Customer.PropertyNames); // ordina le colonne int Len = Customer.PropertyNames.Length; PropertyDescriptor[] props = new PropertyDescriptor[Len]; for(int i=0; i<Len; i++) if(Array.IndexOf(Customer.PropertyNames, pdc[i].Name) == -1) continue; // elimina le colonne non presenti nell'array props[i] = new BizPropertyDescriptor(pdc[i], null); // PropertyDescriptor custom } PropertyDescriptorCollection newpdc = new PropertyDescriptorCollection(props); return newpdc;

Ma non ha forse più senso un business object che li inglobi entrambi?  Gerarchica Nessuna interfaccia. Questo viene gratis quando si implementa bene la ITypedList e il nostro object model è costruito secondo i canoni classici Si potrebbe scrivere una implementazione che nel binding mostri i dati sulla stessa riga mentre gli oggetti restano separati Ma non ha forse più senso un business object che li inglobi entrambi? NWindSale Orders Order Order Products OrderDetails OrderDetail Product Products OrderDetail Product Products OrderDetail Product Nota: l'articolo: http://support.microsoft.com/kb/325682/EN-US/ mostra come creare una JoinView per mostrare dati di due DataTable

 Validazione ed errori Per gestire la validazione dei dati è necessario implementare IDataErrorInfo nella classe collezionata Metodo IDataErrorInfo.Item (indexer) ci passa il nome della colonna (stringa) restituiamo stringa vuota oppure l'errore da mostrare come tooltip Proprietà get di IDataErrorInfo.Error restituiamo stringa vuota oppure l'errore da mostrare nell'header di riga della grid Analogo a impostare la proprietà RowError della DataRow

 Modifiche transazionali L'oggetto collezionato può decidere di gestire la transazionalità delle modifiche implementando IEditableObject Bisogna implementare i 'famosi' metodi BeginEdit, EndEdit, CancelEdit tenendo da parte i valori temporanei delle proprietà fino al commit o rollback della transazione Per evitare equivoci, stiamo parlando di modifiche sull'interfaccia grafica, non del database Per esempio: Utente sceglie la riga EndEdit BeginEdit CancelEdit Cambio di riga Inizio modifiche Pressione tasto ESC

625 righe di collection Dov'è il trucco? Parola d'ordine: "case tools" cioè generatori di codice Se usano CodeDom è meglio perchè possono generare codice VB.net, C#, .... Se usano StringBuilder è facile realizzarli Generare cosa? Il business object base a partire dalla tabella del db Attenzione! I business object spesso non mappano 1:1 con le tabelle quindi un lavoro manuale è sempre dovuto La collection super-accessoriata. Questo è un task semplice: basta partire dall'esempio di questa sessione ed eseguire un banale replace con una regular expression

Alla fine ci siamo rifatti il DataSet ... [Serializable] public class DataSet : MarshalByValueComponent, IListSource, ISupportInitialize, ISerializable [Serializable] public class DataTable : MarshalByValueComponent, IListSource, ISupportInitialize, ISerializable public class DataView : // Analogo della collection di custom object MarshalByValueComponent, IBindingList, IList, ICollection, IEnumerable, ITypedList, ISupportInitialize public class DataRowView : // Analogo del custom object ICustomTypeDescriptor, IEditableObject, IDataErrorInfo public class DataViewManager : // Conserva una lista di impostazioni delle DefaultView MarshalByValueComponent, IBindingList, IList, ICollection, IEnumerable, ITypedList [Serializable] public class DataRow

Ne vale la pena? Se si sviluppa RAD (vita dell'app molto corta), è meglio il DataSet Se il progetto è molto semplice può convenire usare il DataSet Negli altri casi io preferisco custom entities: I business objects e le sue regole non si possono sempre deformare per farli assomigliare ad un database. I business object non sono tabellari e non hanno necessariamente una semplice relazione 1:1 o 1:molti Il db deve rimanere sempre solo un contenitore per la persistenza

La parola ai benchmark ... ... per quello che valgono CustomClass vs DataSet Solo operazioni in memoria (no binding) CustomClass "full-optional" DataSet tipizzato o meno non cambia Risultato velocità: Risultato memoria (bytes in all heaps): DataSet 231'891'952 byte 11,33% Custom 208'285'852 byte 10,18% (misure eseguite con perfmon) public class CustomClass { private int _c0, _c1; private decimal _c2, _c3; private double _c4, _c5; private string _c6, _c7, _c8, _c9; // ... } public TimeSpan DoTest(ITestBiz obj) { DateTime d1 = DateTime.Now; for(int i=0; i<1000000; i++) obj.AddOne(); obj.DeleteOne(); } for(int j=0; j<100; j++) for(int i=0; i<10000; i++) obj.Clear(); DateTime d2 = DateTime.Now; return d2 - d1;

Cosa ci manca ancora? Mantenimento dello stato pre-modifica (aggiornamento e cancellazione) Flag per marcare i nuovi oggetti nella collection Un analogo della DataView Un sistema di persistenza su DataBase ... ORM

Cosa ci porta VS2005? Gestione del DBNull nell'infrastruttura del binding! (niente più problemi con controlli come il datetimepicker) Proprietà NullMapping per la sostituzione del DBNull Gestione visuale delle "List" in controlli come la combo "Smart Captions". Se la colonna si chiama "NomeAzienda" il binding la cambierà automaticamente in "Nome Azienda: " con una regex Eventi "string-typed" dalle colonne del dataset tipizzato (oggi sono generiche) Uso delle partial classes per i DataSet tipizzati L'oggetto TableAdapter per i dataset (che supporta nativamente i DBNull) BindingSource e BindingNavigator (nella beta1 si chiamavano DataConnector e DataNavigator) ... comodo ma non può far altro che usare reflection e quindi è meno efficente della soluzione presentata

... che si fa tutto senza scrivere una riga di codice  Domande? E poi non dite che è la solita sessione ... ... dove si racconta la solita storia ... ... che si fa tutto senza scrivere una riga di codice 