Uno degli slogan che hanno accompagnato C# fin dalla sua nascita lo presenta come «un linguaggio facile come Java, potente come il C++». In effetti, come vedremo, le somiglianze con i due linguaggi sono molte, e non solo dal punto di vista della sintassi. Le differenze comunque ci sono ma la loro trattazione esula dagli obiettivi di questo corso, che si propone, invece, di analizzare nello specifico il linguaggio C#. Chi fosse interessato a differenze e somilgianze, può trovare maggiori informazioni usando i collegamenti a fine lezione (in lingua inglese) oppure, avendo a disposizione Visual Studio 2005, si possono trovare maggiori dettagli sull'argomento cercando «Comparison Between Java and C#» e «Comparison Between C++ and C#» nella guida in linea. Questa guida, in una prima fase, introdurrà ai concetti chiave di questo linguaggio, nella seconda parte del corso invece, ci si concentrerà sull'ambiente di sviluppo Visual Studio 2005 e sulle nuove funzionalità introdotte dalla versione 2.0 del Framework. Infine fornirà una panoramica degli strumenti messi a disposizione per la realizzazione di applicazioni web con ASP .NET. Il corso si rivolge a chi ha già dimestichezza con la programmazione ad oggetti e con linguaggi simili a Java o C++. Sono volutamente tralasciate le spiegazioni sulla sintassi di base: per esempio i costrutti if, switch, for, while, etc. Chi già conosce linguaggi come c++, Java, php o Javascript non vedrà grosse novità. Chi invece non avesse familiarità con i linguaggi cosiddetti "c-like" può trovare in fondo alla lezione un link per approfondire. In ogni caso, dove necessario per la comprensione del corso, saranno indicati esplicitamente i collegamenti con i concetti trattati su altre fonti. In queste prime pagine ci occuperemo delle caratteristiche proprie di C# e delle innovazioni che introduce nel modo di programmare. Al momento della stesura di questa guida, il Framework .NET 2.0 e Visual Studio 2005 sono ancora in fase di beta test (in particolare, è stato usato Visual Studio 2005 Beta 2), quindi è possibile, anche se in linea di massima non dovrebbe accadere, che alcune delle caratteristiche mostrate saranno diverse dalla versione finale. Poiché la versione italiana verrà rilasciata solo dopo il rilascio ufficiale del prodotto, si è fatto riferimento alle voci dei menù e delle finestre della versione inglese; ove possibile, è stata fornita una traduzione, che però in alcuni casi potrebbe non corrispondere con l'effettiva localizzazione in italiano. Questa guida si propone di suscitare curiosità sul mondo di C#, fornendo però gli strumenti minimi necessari ad approfondire individualmente gli argomenti affrontati.
Più che stabilire quale sia il "migliore", è interessante capire le peculiarità di ciascun linguaggio. Ci soffermeremo sulla valutazione delle differenze più importanti. Ad una prima analisi è evidente che VB.NET risulta la scelta preferita per chi proviene dalle versioni precedenti di VB e ASP-VBScript, mentre C# è più accattivante per chi proviene da esperienze con C++ e Java. La sintassi di C# assomiglia moltissimo a quella di Java, mentre quella di VB.NET è evoluzione del Visual Basic. La differenza più importante nel passaggio dal vecchio al nuovo non riguarda tanto la sintassi quanto la sensazione di novità in termini di approccio alla programmazione ad oggetti. Chi è abituato a lavorare in C++ o Java trova un ambiente in cui i concetti sono analoghi quando non del tutto sovrapposti. Per esempio in .NET come in Java tutto è un oggetto: è abbandonato ogni tipo di approccio ibrido con la programmazione strutturata in stile C++. Quindi chi proviene dai "vecchi" ASP e VB si trova davanti ad un linguaggio simile in alcuni aspetti della sintassi di base ma con un approccio alla programmazione a oggetti che è comune a tutto il Framework ed è più proprio di Java e compagnia. C# è un linguaggio nuovo, mentre VB .NET porta con sé l'eredità di tutte le versioni precedenti di Visual Basic (la sintassi di VB .NET, seppur aggiornata con il supporto agli oggetti, è praticamente la stessa di quella di Visual Basic 4.0, rilasciato nell'ormai lontano 1996). Un primo aspetto evidente è che il codice scritto in VB .NET risulta più lungo rispetto all'equivalente in C#. Consideriamo, per esempio, una funzione che prende in ingresso due numeri e ne calcola la media:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Al di là delle differenze che riguardano la sintassi, C# permette di realizzare cose che in VB .NET non si possono fare, e viceversa. Ad esempio, C#, mostrando la sua derivazione dal C++, consente di utilizzare i puntatori, cosa che VB .NET non permette. Alcune differenze architetturali sono state colmate con la versione 2.0 del Framework, che introduce anche per Visual Basic .NET l'overloading degli operatori (altra caratteristica che C# ha preso da C++) e la possibilità di documentare il codice scritto utilizzando il linguaggio XML. Infatti C# permette la documentazione delle classi usando dei tag nel codice in modo molto somigliante ai commenti per JavaDocs. VB .NET, in particolare con la nuova versione del Framework, rende ancora più semplice e veloce la scrittura di applicazioni: tra i tanti esempi che si potrebbero fare a riguardo, citiamo il namespace My , che fornisce un rapido accesso a tutta una serie di proprietà e metodi di uso comune, consentendo uno sviluppo più efficiente. Le informazioni contenute nel namespace My sono comunque disponibili anche da C#, ma la sua presenza in VB .NET rende molto più agevole lo svolgimento di alcuni compiti. Ad esempio, per scaricare un file da Internet, usando Visual Basic .NET con il Framework 2.0 è sufficiente un'istruzione:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Inoltre, l'elenco dei membri che appare grazie all'IntelliSense in VB .NET è diviso in due schede in cui vengono messi in evidenza gli elementi di uso comune, facilitando la selezione della voce desiderata. In C# l'elenco dei membri viene sempre visualizzato nella sua interezza. Figura 1: L'IntelliSense di Visual Basic .NET Questa rapida carrellata sulle differenze tra C# e Visual Basic .NET non ha la pretesa di essere esaustiva: per maggiori informazioni (riguardanti soprattutto le più evidenti diversità di sintassi), consultare i collegamenti a fine pagina. Inoltre, disponendo di Visual Studio 2005, è possibile ottenere maggiori dettagli sull'argomento cercando Language Equivalents nella guida in linea.
Perfavore,
Entra
oppure
Registrati
per vedere i Link!
dal sito Microsoft.Dunque è sufficiente usare un editor di testi per sviluppare applicazioni .NET, anche se quando ci si orientasse verso programmi più complessi e dotati di interfaccia grafica, l'adozione di un ambiente di sviluppo visuale diventa quasi indispensabile. Realizziamo subito il nostro primo programma. Costruiremo un'applicazione "console", ovvero eseguibile dal prompt dei comandi. Per scrivere un programma di questo tipo non è strettamente necessario un ambiente di sviluppo come Visual Studio (che analizzeremo in dettaglio nelle prossime Lezioni), data l'assenza di elementi grafici o di connessioni complesse tra classi. Pensiamo di voler realizzare la classica applicazione che stampa a video la stringa "Ciao Mondo!", aspetta che l'utente prema il tasto INVIO e, quindi, termina. Il codice è il seguente:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Con la versione 2.0 di .NET, nel menù Start di Windows comparirà il gruppo Microsoft .NET Framework SDK v2.0, al cui interno si trova il comando SDK Command Prompt che permette di aprire un prompt dei comandi con le variabili di sistema per l'uso degli strumenti a riga di comando del Framework già impostate. Quindi possiamo spostarci nella cartella in cui è stato salvato il file «Hello.cs» e digitare il comando:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
L'espressione «public class HelloWorld» serve per definire una classe di nome «HelloWorld». Quello di classe è un concetto fondamentale, che approfondiremo nel corso delle prossime lezioni, al momento basti sapere che tutto il codice di un programma C# definisce classi e scambi di informazioni tra classi. main è un metodo particolare. Il cosiddetto punto di ingresso dell'applicazione, ovvero il primo metodo che viene richiamato quando si avvia il programma. Tutti i programmi eseguibili realizzati con C#, compresi quelli per Windows, devono avere una (e solo una) classe con all'interno un metodo main, altrimenti in fase di esecuzione si otterrà un messaggio di errore. L'istruzione System.Console.WriteLine() stampa a video il messaggio, mentre System.Console.ReadLine() fa sì che l'applicazione aspetti che l'utente prema il tasto INVIO prima di terminare. Abbiamo così realizzato un semplice programma in C#, per prendere subito confidenza con i primi strumenti e per stimolare la nostra curiosità su alcuni concetti che saranno trattati con maggior dettaglio nelle prossime lezioni. L'esempio che abbiamo costruito può essere scaricato Perfavore,
Entra
oppure
Registrati
per vedere i Link!
Per fare un'esempio si pensi alle automobili: ogni automobile è diversa da un'altra ma tutte hanno quattro ruote un propulsore e compiono l'azione di avanzare o frenare. Questi elementi comuni le fanno rientrare in un unico concetto. Un'unica classe. Più praticamente una classe è una collezione di variabili, metodi e proprietà. Anche in questo caso, C# riprende la sintassi di Java dove per definire una classe si usa il costrutto class.
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Possiamo però cosiderare le istanze di una classe, ovvero gli oggetti che realizzano il concetto di classe, come variabili definite da un certo tipo di dato.
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Il costruttore è utilizzato per impostare le proprietà che la classe deve avere al momento della sua creazione: nel nostro esempio, quando si crea una istanza della classe Persona, le sue variabili mNome e mCognome assumono i valori specificati nel relativo argomento del costruttore. Dichiarazione dei metodi I metodi di una classe possono essere definiti come public, private, protected oppure internal (Friend in Visual Basic .NET): queste parole chiave vengono solitamente chiamate modificatori di accesso. Con public, una routine diventa accessibile da tutte le istanze della classe. Private, invece, impedisce che la routine sia visibile al di fuori della classe di in cui è definita. Se non si specifica il modificatore di accesso, private è il valore predefinito. Ad esempio, utilizzando ancora la nostra classe Persona:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
In pratica, protected equivale a private, con la differenza che il metodo è visibile anche alle classi che ereditano da quella principale. Infine, ciò che è dichiarato come internal è visibile solo all'interno dell'assembly dell'applicazione; per il concetto di assembly fare riferimento alle Lezioni dedicate all'uso di Visual Studio 2005. Dopo il modificatore di accesso del metodo, nella dichiarazione è necessario specificare il tipo di dato restituito. È possibile indicare un qualsiasi tipo di dato: int, string, byte, etc. Si può specificare anche il nome di una classe, poiché, ricordiamo, una classe è un tipo. Questo tipo di metodi corrisponde alle Function di VB. Per restituire il valore, è necessario utilizzare la parola chiave return, seguita da una qualsiasi espressione che abbia lo stesso tipo del valore di ritorno del metodo. Tale istruzione causa anche l'uscita dal metodo. Ad esempio:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Le funzioni di Visual Basic, invece, possono non presentare il return: in tal caso il valore restituito è quello di default per il particolare tipo di dati. I metodi che non restituiscono un valore, come StampaMessaggio() e Appoggio() dell'esempio, hanno tipo void; essi corrispondono alle Sub di Visual Basic. Si può comunque usare la parola return in un metodo void, che in questo caso ha il solo scopo di uscire dalla procedura: in questo caso, quindi return non deve essere seguito da alcuna espressione. Le proprietà
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Il codice del blocco set, invece, viene eseguito quando si modifica il valore della proprietà; la parola chiave value contiene il nuovo valore da assegnare. L'utilizzo delle proprietà è intuitivo:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
È lecito domandarsi perché utilizzare le proprietà, quando si potrebbe più semplicemente rendere pubbliche le variabili mNome e mCognome. Conviene avere una classe con membri privati accessibili solo tramite proprietà quando si devono effettuare dei controlli sui valori assegnati ai membri stessi. Ad esempio, supponiamo di voler impedire che l'utente inserisca un nome o un cognome vuoto: se impostiamo le variabili mNome e mCognome come pubbliche questo controllo non può essere effettuato. Infatti si ha libero accesso alle variabili che possono essere impostate su qualunque stringa valida (compresa, dunque, la stringa vuota). Per risolvere il problema, è sufficiente definire i membri come privati e modificare la proprietà Nome nel modo seguente:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
string.Empty è un campo a sola lettura che rappresenta la stringa vuota. Se Nome oppure Cognome vengono impostati sulla stringa vuota, questo codice li definisce, rispettivamente, come Nessun nome e Nessun cognome. Notiamo che, per ottenere un comportamento coerente di tutta la classe, anche il costruttore deve essere modificato in modo da effettuare un controllo sugli argomenti. È buona norma definire delle proprietà che consentano di modificare i valori delle variabili utilizzate da una classe, in modo da avere un maggior controllo sui dati specificati, piuttosto che dare libero accesso alle variabili stesse. Le proprietà possono anche essere di sola lettura, se dispongono del solo blocco get, oppure di sola scrittura, se hanno solo il codice associato al set. Per ottenere un comportamento analogo in Java oppure in C++, è necessario definire due metodi distinti, i cosiddetti metodi getter (per recuperare il valore) e setter (per impostarlo). Il codice completo della classe può essere scaricato qui. Nel file da scaricare è incluso un semplicissimo esempio di uso della classe Persona. Metodi «statici» Negli esempi visti finora, per accedere ai metodi della classe Persona occorreva creare un'istanza della classe. In alcuni casi, tuttavia, può risultare utile avere delle procedure che non hanno bisogno di un'istanza per essere utilizzate, ma che possono essere richiamate semplicemente con il nome della classe. Ad esempio, supponiamo che il metodo Quadrato di cui abbiamo parlato in precedenza sia contenuto nella classe «Matematica». È sensato pensare che una procedura di questo tipo possa essere richiamata senza dover prima creare un'istanza della classe che la contiene. Per questo si usa la parola chiave static (che corrisponde allo Shared di VB .NET): Una classe può contenere anche un altro tipo di metodi, le cosiddette proprietà. Si tratta di particolari routine che permettano di leggere e/o impostare i valori di determinate proprietà di una classe. Aggiungiamo, per esempio, la seguente proprietà alla classe Persona:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Notiamo che le funzioni WriteLine() e ReadLine() della classe Console, che abbiamo introdotto in precedenza, sono proprio metodi statici. I namespace Più classi possono essere raggruppate in un unico namespace. Ad esempio:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
È possibile definire namespace annidati, ad esempio:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Per non dover indicare ogni volta i namespace in cui si trovano le classi che si stanno utilizzando, è possibile utilizzare la parola chiave using (analoga a import di Java), con cui si specifica in quali namespace devono essere cercate le classi. Le clausole using devono essere specificate all'inizio della classe, prima di qualunque altra istruzione. Ad esempio, nel programma «HelloWorld» realizzato nelle precedenti lezioni si fa uso della classe Console, che è contenuta nel namespace System; invece di indicarlo esplicitamente, è possibile ricorrere alla parola chiave using:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Perfavore,
Entra
oppure
Registrati
per vedere i Link!
per scaricare il codice sorgente della classe Matematica, compreso un esempio del suo utilizzo.
Il tipo struct permette di definire nuovi tipi di dati a partire da quelli esistenti:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Questo perché il tipo struct è molto potente: può essere dotato di un costruttore (che si comporta esattamente come il costruttore di una classe), di proprietà e di metodi. Modifichiamo la struttura Persona aggiungendovi un costruttore e una proprietà che restituisce il nome completo, quindi riprendiamo il nostro primo programma ed aggiorniamolo per mostrare l'uso della struct:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Fare clic qui per scaricare l'esempio. A questo punto è naturale chiedersi quali siano le differenze tra struct e class. La spiegazione è fornita dalla guida in linea: "Il tipo struct è adatto alla rappresentazione di oggetti leggeri [...] Se ad esempio si dichiara una matrice di 1.000 oggetti [classi] Point, si allocherà ulteriore memoria per i riferimenti a ciascun oggetto. In questo caso la struttura risulta meno onerosa". Inoltre una struct può implementare interfacce ma non può ereditare. Le enum consentono di associare nomi simbolici a costanti numeriche. Il costrutto deriva dal C++ dove i membri delle enum sono sempre di tipo «int», mentre in C# è possibile indicarne esplicitamente il tipo:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Concludiamo questa Lezione con qualche cenno sul passaggio dei parametri ai metodi. I parametri in C# possono essere passati in tre modi: in, out e ref. Queste parole chiave determinano cosa accade alla variabile passata come argomento quando si esce dal metodo. in è il tipo di passaggio predefinito: la routine non può modificare la variabile, o, meglio, qualunque modifica della variabile interna al metodo viene persa quando si esce dal suo scope (il tipico passaggio "per valore"). ref e out sono i classici passaggi di parametro per riferimento. Viene passato il riferimento (il puntatore) alla variabile e non il suo valore, così anche nello scope del metodo si fa riferimento allo stasso oggetto in memoria. La differenza tra ref e out è che ref richiede che si inizializzi la variabile prima della chiamata del metodo, mentre con out è sufficiente dichiarare la variabile e passarla senza inizializzazione. In pratica con out è possibile inizializzare intere strutture dati dall'interno di un metodo. Vediamo ora alcuni semplici esempi per chiarire quanto illustrato:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Tornando all'esempio delle automobili potremmo avere come classi derivate da automobili le sottoclassi: «auto con cambio manuale» e «auto con cambio automatico». Entrambe le sottoclassi ereditano tutte le proprietà e i comportamenti della classe base ma specializzano il modo di cambiare le marce. Tutte le classi del Framework .NET ereditano implicitamente dalla classe base Object. In C# la relazione di ereditarietà tra le classi si esprime usando i due punti ( che equivalgono a Inherits di VB.NET . Riprendiamo una parte della classe Persona che abbiamo realizzato in precedenza:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Ad esempio, all'interno di Studente è possibile utilizzare la variabile mCognome, che in Persona è definita protected, mentre mNome non è visibile, poiché il modificatore di accesso predefinito è private. Esaminiamo il frammento
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Se avessimo voluto che il nome della persona, indipendentemente da quanto indicato nel costruttore di Studente, fosse sempre "Pippo", mentre il cognome fosse quello passato, sarebbe stato sufficiente scrivere:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Poiché la classe Persona non ha un costruttore senza argomenti, bisogna indicare esplicitamente tramite la parola chiave «base» quale costruttore richiamare. Se invece Persona avesse avuto un costruttore privo di argomenti, «base» non sarebbe servita. Oltre che a questo scopo, «base» serve, in generale, per avere accesso ai metodi, alle variabili ed alle proprietà della classe che si sta derivando. Il corrispondente di «base» in Visual Basic è la parola chiave MyBase. Provando a dichiarare oggetti di tipo Persona e Studente, si ottiene quanto segue:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Perfavore,
Entra
oppure
Registrati
per vedere i Link!
per scaricare le due classi Persona e Studente.Grazie all'ereditarietà, dove è previsto l'uso di una certa classe, è quasi sempre possibile utilizzare una classe derivata. Questo è, probabilmente, uno degli aspetti più interessanti dell'ereditarietà. Per esempio, supponiamo di avere una funzione che, ricevuti come argomenti due oggetti di tipo Persona, restituisce true se i loro nomi sono uguali:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
È possibile scaricare un esempio di utilizzo cliccando Perfavore,
Entra
oppure
Registrati
per vedere i Link!
L'ereditarietà è singola, in C# come in VB.NET, ovvero una classe può avere solo una classe base, a differenza del C++, che supporta l'ereditarietà multipla: in altre parole, non è possibile definire una classe C che eredita contemporaneamente da A e da B. Torneremo su questi concetti più avanti.
Continuiamo ad usare le nostre classi Persona e Studente realizzate nelle lezione precedente per capire il concetto di polimorfismo. Inizialmente, avevamo definito il metodo pubblico StampaMessaggio() nella classe Persona, ma non ne abbiamo ancora scritto il corpo. Vogliamo fare in modo che questa routine stampi a video le informazioni sulla persona. È naturale pensare che, analogamente, anche la classe Studente abbia un metodo StampaMessaggio() che mostri, oltre alle informazioni sulla persona, anche quelle proprie di uno studente. Perciò dobbiamo definire i metodi nel modo seguente:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
A seconda che si dichiari un oggetto di tipo Persona oppure Studente, verrà richiamata la routine StampaMessaggio() corrispondente. Per fare questo, abbiamo usato il polimorfismo: il metodo StampaMessaggio() nella classe base è stato dichiarato usando la parola chiave «virtual» (che corrisponde a Overridable in Visual Basic .NET): con essa si indica che è possibile avere un'altra definizione per la stessa routine in una classe derivata. In Studente, infatti, StampaMessaggio() è stato definito specificando la parola chiave «override» (Overrides in VB): in questo modo si dice che tale funzione sovrascrive un metodo con lo stesso nome che è stato definito nella classe base. In alcuni casi può essere necessario, all'interno del metodo ridefinito, richiamare il metodo che si sta ridefinendo. Nel nostro esempio, il metodo StampaMessaggio() della classe Studente potrebbe richiamare il metodo StampaMessaggio() di Persona, che si occupa già di mostrare il nome e il cognome, limitandosi quindi a stampare solo le informazioni proprie di uno studente. Per fare questo, si deve usare la parola chiave «base», che, come già accennato nella lezione precedente, consente di avere accesso alla classe che si sta derivando; alla luce di queste considerazioni, il metodo StampaMessaggio() di Studente diventa:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
L'esempio che abbiamo realizzato può essere scaricato cliccando qui. C'è anche un altro modo per sfruttare il polimorfismo, ovvero usando la parola chiave «new» (equivalente a Shadows in VB .NET), che nasconde una definizione della classe base con lo stesso nome. L'esempio sopra riportato, usando «new», diventa:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
È possibile scaricare le due classi modificate cliccando Perfavore,
Entra
oppure
Registrati
per vedere i Link!
È importante notare che, usando la coppia «virtual» e «override», il metodo che sovrascrive una routine della classe base deve avere non solo lo stesso nome, ma anche lo stesso numero di argomenti e dello stesso tipo. Invece, usando «new», è possibile ridefinire un metodo completatmente. Con «new» si può addirittura nascondere una variabile della classe base con un intero metodo nella classe derivata. Questa rapida panoramica è solo una introduzione al polimorfismo, per approfondire è sempre utile consultare la Guida in linea.
Per firma di un metodo si intede il numero e/o il tipo di argomenti nella dichiarazione. Sulla base degli argomenti effettivamente passati alla routine, verrà riconosciuta la firma e richiamato il metodo corretto. Vediamo subito un esempio:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Questa soluzione è da preferire poiché, in caso di modifiche al costruttore, è sufficiente intervenire su un solo punto del codice. Se, ad esempio, dopo aver creato la classe Persona, si decidesse che il nome deve essere sempre preceduto dalla stringa "Sig.", nel primo esempio di overloading del costruttore sarebbe stato necessario modificare il codice in due parti diverse. Nel caso in cui siano previsti più costruttori, le porzioni di codice da cambiare possono essere più numerose e, quindi, aumenta la probabilità di dimenticarsi qualche modifica. La nuova classe Persona è disponibile Perfavore,
Entra
oppure
Registrati
per vedere i Link!
Overloading degli operatori L'overloading degli operatori, derivato dal C++, consiste nel ridefinire il comportamento di operatori come +, - , <, >, ==, etc., affinchè assumano comportamenti a seconda degli oggetti cui sono applicati. C# supporta l'overloading degli operatori a partire dalla sua prima versione, mentre VB.NET ha introdotto questa funzionalità solo con la versione 2.0 del Framework. Partiamo come sempre dalla classe Persona. Non avendo altre informazioni, C# assume che due variabili di tipo Persona siano uguali se fanno riferimento all'istanza dello stesso oggetto, ovvero:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Per fare questo, o ogni volta facciamo il controllo sulle proprietà Nome e Cognome oppure, più semplicemente, ridefiniamo l'operatore '==' per la classe Persona creando un metodo con la parola chiave «operator»:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
L'overloading degli operatori è sempre definito con metodi statici. Dopo l'indicazione del tipo di dato restituito (solitamente bool oppure lo stesso tipo della classe per cui si sta creando l'overloading, a seconda dell'operatore in questione), è necessario specificare l'operatore che si sta ridefinendo. Sulla guida in linea troviamo l'elenco di tutti gli operatori che possono essere sottoposti ad overloading. Infine, bisogna indicare a quali tipi di dati si applica: nel nostro esempio, '==' e '!=' si applicano a oggetti della classe Persona. Gli argomenti del metodo sono due nel caso di operatori binari (come mostrato nel nostro esempio), oppure uno solo se l'operatatore è unario (++, --, ecc.). Ridefinendo gli operatori '==' e '!=', il compilatore si aspetta che vengano anche ridefiniti i metodi Equals() e GetHashCode(), che ogni classe possiede in quanto li eredita dalla classe base Object. Ad ogni modo, se non vengono specificati, si ottiene solo un warning di compilazione. Definiamoli comunque, per avere una classe più robusta:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Altrimenti, l'oggetto corrente viene convertito ad Object, quindi si usa il confronto standard, per cui due variabili di tipo object sono uguali se fanno riferimento all'istanza dello stesso oggetto. Grazie a questa ridefinizione, ora possiamo ottenere il risultato desiderato:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Perfavore,
Entra
oppure
Registrati
per vedere i Link!
per scaricare la classe Persona realizzata fino a questo punto.A titolo di esempio, nel file da scaricare è stato ridefinito anche l'operatore '+', che "somma" due persone, ovvero crea una nuova Persona il cui nome e cognome sono la concatenazione dei nomi e dei cognomi delle persone di partenza. Al di là dell'utilità di un'operazione del genere, si tratta comunque di un esempio in più da tenere in considerazione.
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Oltre a ciò, è possibile dichiarare un'altra serie di metodi e proprietà che devono essere obbligatoriamente implementate dalle classi che ereditano da essa: i cosiddetti metodi e proprietà astratti. Nel nostro caso, la classe che eredita da Figura deve fornire una implementazione delle proprietà Perimetro e Area (dalla definizione si comprende che saranno di sola lettura, se fossero state di lettura/scrittura avremmo avuto get; set;) e del metodo Disegna. La classe Quadrato eredita correttamente da Figura:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Ad esempio, eliminando il metodo Disegna dalla classe Quadrato, la compilazione fallisce segnalando che 'Quadrato' non implementa il metodo astratto ereditato Figura.Disegna(). Per le classi astratte valgono le stesse considerazioni fatte a proposito dell'ereditarietà, ovvero se un metodo richiede una classe astratta come argomento, al suo posto potrà essere utilizzata una qualunque classe che eredita da essa. In VB.NET una classe astratta si dichiara con MustInherit e un metodo astratto con MustOverride. Fare clic Perfavore,
Entra
oppure
Registrati
per vedere i Link!
per scaricare l'esempio che abbiamo realizzato; nel file ZIP è disponibile anche la classe triangolo.
Questo significa, in primo luogo, che tutti i metodi e le proprietà definite all'interno di un'interfaccia sono implicitamente astratti, ovvero non è possibile fornirne l'implementazione all'interno dell'interfaccia stessa. Per creare un'interfaccia, si utilizza la parola chiave «interface»:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Un'interfaccia non può contenere variabili, struct, enum e, come già accennato, implementazioni di metodi (tutte cose che, invece, sono consentite nelle classi astratte). Un'interfaccia viene implementata da una classe. Per indicare che una classe implementa un'interfaccia, in C# si usa il carattere ":", lo stesso con cui si esprime l'ereditarietà tra classi (in VB.NET si usa la parola chiave Implements):
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
In VB.NET, invece, i nomi assegnati ai metodi non sono vincolanti, poiché il metodo dell'interfaccia che si sta implementando è indicato esplicitamente. Come già visto in precedenza, una classe può ereditare da una sola classe base, mentre può implementare un numero illimitato di interfacce: in questo caso, è necessario definire i metodi e le proprietà di tutte le interfacce:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Supponiamo che IEsempio1 ed IEsempio2 contengano un metodo con lo stesso nome, ad esempio un metodo void Calcola(). La classe Studente deve definirli entrambi: per evitare conflitti, i nomi dei metodi devono essere preceduti dal nome dall'interfaccia in cui sono definiti:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Un oggetto che implementa un'interfaccia, inoltre, può essere utilizzato in tutte le parti del codice in cui è richiesta tale interfaccia, quindi anche le interfacce definiscono una nozione di ereditarietà. Sia le interfacce sia le classi astratte servono per definire una serie di funzionalità di base che devono essere realizzate dalle classi che le ereditano o le implementano. La scelta di utilizzare un'interfaccia oppure una classe astratta può a volte risultare difficile. MSDN consiglia: «Mediante le classi astratte possono essere forniti anche membri che sono già stati implementati. Pertanto, con una classe astratta è possibile garantire una certa quantità di funzionalità identiche, a differenza di quanto avviene con un'interfaccia (che non può contenere alcuna implementazione)[...]. Se le funzionalità da creare saranno utilizzate in una vasta gamma di oggetti diversi, usare un'interfaccia. Le classi astratte devono essere usate principalmente per gli oggetti strettamente correlati, mentre le interfacce sono più adatte a fornire funzionalità comuni a classi non correlate».
Lo strumento "principe" per la realizzazione di applicazioni che si basano sul Framework .NET è Visual Studio. Alla sua ultima versione 2005 (in fase di beta testing al momento della stesura di questa guida), questo ambiente di sviluppo migliora sensibilmente le caratteristiche di usabilità e potenza che lo hanno da sempre contraddistinto. Figura 1: L'ambiente di sviluppo Visual Studio 2005 L'interfaccia di Visual Studio 2005 dovrebbe risultare familiare a chi ne ha già utilizzata una versione precedente. Alcuni riferimenti possiamo trovarli a fine pagina. La procedura per creare una applicazione Windows è simile alla precendete versione anche se la finestra di dialogo Nuovo Progetto (New Project) è cambiata, come visibile in figura. Figura 2: La nuova finestra di dialogo New Project Le novità introdotte dalla nuova release di Visual Studio, relativamente al miglioramento della produttività, possono essere riassunte in cinque concetti essenziali: Smart Tag: Visual Studio 2005 supporta un discreto numero di Smart Tag per velocizzare le operazioni più comuni; IntelliSense: ora il completamento automatico del codice si attiva non appena si inizia a digitare qualcosa nell'editor. È attivo anche durante la scrittura di pagine ASP .NET Refactoring: con questo termine si intende una serie di funzionalità che permettono di modificare velocemente e sistematicamente il codice scritto. tra le altre caratteristiche, cambiando il nome di una variabile, di un metodo o di una proprietà, uno Smart Tag consente di rinominare automaticamente tutte le occorrenze della stringa modificata. Figura 3: Il refactoring di Visual Studio 2005 in azione Code Snippets e Surrounding: gli "snippet" sono porzioni di codice di uso comune, come il codice dei costrutti for e while, che possono essere inseriti facendo clic col tasto destro del mouse nella finestra del codice e selezionando il comando Insert Snippet..., oppure, più semplicemente, digitando il nome dello snippet e premendo due volte il tasto TAB. Queste porzioni di codice possono contenere dei parametri. In tal caso, dopo l'inserimento, il cursore si posiziona automaticamente sul primo di essi: per spostarsi tra i parametri, si usa il tasto TAB. Il Surrounding, invece, è letteralmente la possibilità di "circondare" un blocco di istruzioni con un certo costrutto, ad esempio for oppure try...catch...finally Figura 4: Inserimento di uno snippet di codice Finestra dei task comuni: selezionando un controllo in una Windows Form, in alto a destra viene visualizzata un piccolo riquadro con una freccia verso destra: facendo clic su di esso, compare una finestra che consente di impostare velocemente le proprietà usate più di frequente per l'oggetto in questione. Altra novità interessante, forse una delle più richieste, è la funzionalità di Edit & Continue, che deriva dalle vecchie versioni di Visual Basic e che finalmente è supportata anche da C#. Consiste nella possibilità di modificare il codice durante il debug del programma senza interromperne l'esecuzione (ovviamente a patto di non alterare il flusso delle istruzioni). Ci sono miglioramenti volti a rendere ancora più semplice il debugging delle applicazioni e il Class Designer (Progettazione Classi), per costruire in modo grafico lo schema delle classi, usando un approccio in stile UML.
Creiamo una nuova Windows Application (applicazione Windows) con il linguaggio C#, come indicato nella lezione precedente. Il progetto include di default una Windows Form, contenuta in un file di nome Form1.cs. Premiamo il tasto F7 per visualizzare il codice sorgente; in alternativa, è possibile fare clic con il tasto destro del mouse sul file «Form1.cs» visualizzato nel Solution Explorer (Esplora soluzioni) e selezionare il comando View code (Visualizza codice). Viene mostrato il codice:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
L'insieme di tutte le classi fornite dal Framework .NET prende il nome Base class library. Si tratta di una raccolta vastissima, ed è impossibile anche solo citare tutte le classi che contiene. Viene poi definito il namespace WindowsApplication1. Tutte le Windows Form create con Visual Studio, così come le classi, le interfacce, gli user control, etc., sono automaticamente inserite all'interno di un namespace, che per impostazione predefinita ha lo stesso nome del progetto. Questa impostazione può essere cambiata facendo clic con il pulsante destro del mouse sul nome del progetto all'interno del Solution Explorer e selezionando il comando Properties (Proprietà). VB.NET, al contrario, di default non include le classi create all'interno di namespace. Il codice evidenzia che anche una Windows Form è una classe, che eredita dalla classe «Form». Osserviamo la parola chiave partial, una novità della versione 2.0 del Framework che permette di definire classi "parziali". Di norma, ogni classe risiede in un file separato, ma utilizzando partial è possibile creare classi definite su più file. Da ciascun file parziale è possibile accedere alle variabili, ai metodi, alle proprietà, di tutti gli altri file parziali relativi alla stessa classe, proprio come se l'intera dichiarazione della classe fosse contenuta in un unico file. Questo nuovo concetto favorisce una maggiore pulizia e leggibilità del codice della Windows Form: il codice di progettazione, che imposta le proprietà della finestra e dei controlli in essa inseriti, in precedenza veniva salvato nello stesso file del form, all'interno della region Windows Form Designer generated code (Codice generato da Progrettazione Windows Form), mentre ora è memorizzato in un file di supporto gestito internamente dall'ambiente di sviluppo e chiamato Form1.Designer.cs (al posto di Form1 c'è il nome del form). Vedremo che questo concetto somiglia molto a quello di code behind nelle applicazioni Web. L'unico indizio dell'esistenza di questo file è il metodo InitializeComponent() che viene richiamato nel costruttore del form: esso, come nelle precedenti versioni, ha il compito di inizializzare tutti gli oggetti contenuti nel form. Per visualizzare il contenuto del file Form1.Designer.cs, premere il pulsante + posto a fianco del nome del form nel Solution Explorer. In VB.NET, invece, il file del Designer di default è nascosto. Per visualizzarlo, è necessario fare clic sul pulsante Show All Files all'interno del Solution Explorer. Inoltre, in VB la Windows Form non è dichiarata come «Partial» (anche se, in realtà, anch'essa è una classe parziale). Figura 1. Il Solution Explorer Le classi parziali e il loro utilizzo nelle Windows Form potrebbero sembrare novità di poco conto che, però, si fanno apprezzare quando si crea una finestra con un numero elevato di controlli. Nelle precedenti versioni il file di definizione della Windows Form si reimpiva di una gran quantità di codice mantenuto dall'ambiente di sviluppo (che, quindi, l'utente non avrebbe dovuto modificare, come indicato chiaramente dai commenti), a discapito della leggibilità. Visual Studio 2005 consente un posizionamento dei controlli sulla Windows Form molto più agevole che in passato: è sparita la griglia che ricopriva il form in fase di progettazione, poiché ora i controlli sembrano "calamitati" dai bordi della finestra e dagli altri oggetti; inoltre, durante le operazioni di trascinamento, vengono visualizzate delle linee guida per consentire un posizionamento più preciso degli elementi nella finestra.
Continuiamo a lavorare con la Windows Form realizzata nella scorsa lezione, precisando che quanto diremo in seguito a proposito degli eventi vale per ogni tipo di controllo, sia esso una form, un pulsante, una casella di testo, un comando di menu, etc. Possiamo definire un evento come il verificarsi di una condizione: dalla pressione di un pulsante, alla digitazione in una casella di testo. Quando si verifica una di queste condizioni, diciamo che il controllo genera (oppure lancia) un evento. Ad esempio, quando si preme il pulsante sinistro del mouse su di un bottone, esso genera l'evento «Click». Ad ogni evento può essere associata una azione descritta da una particolare routine che viene eseguita ogni volta che l'evento si verifica. Supponiamo di voler eseguire una certa azione in fase di caricamento del form. Occorre anzitutto creare un gestore di eventi (detto Event Handler) per l'evento «Load» della finestra Form1. Aggiungiamo il seguente codice nel costruttore della classe:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Di seguito, dopo il punto, si indica il nome dell'evento da gestire: gli eventi disponibili sono riconoscibili, nell'elenco visualizzato tramite l'IntelliSense, dal simbolo di un fulmine. Figura 1: Gli eventi del form L' operatore '+=' indica che si sta aggiungendo un gestore per l'evento. Si usa '+=', e non solo '=', perché è possibile specificare più handler per lo stesso evento. L'IntelliSense ci viene ancora una volta in aiuto, proponendoci un nome per il gestore degli eventi: è sufficiente premere il tasto TAB per confermare il suggerimento. Il metodo che rappresenta l'azione collegata all'evento viene detto "delegato" (delegate). Infatti viene delegata a quel metodo la gestione dell'evento. Form1_Load() in questo caso è un delegato. Questo metodo di creazione degli event handler corrisponde ad «AddHandler» in VB.NET EventHandler e tutte le classi derivate sono gestori di eventi. Ogni oggetto istanza di EventHanlder richiede il riferimento a un delegato per la gestione di un evento, la stringa "Form1_Load" senza parentesi altro non è che un riferimento (puntatore) al metodo Form1_Load(). Un delegato in astratto ha però una certa firma e per rimpiazzarlo con un altro metodo come Form_Load() occorre che questo abbia i medesimi argomenti in tipo e numero e lo stesso tipo di ritorno. Con EventHandler(Form1_Load) si esprime il fatto che il metodo Form1_Load() avrà argomenti uguali in numero e tipo a quelli indicati nella dichiarazione del delegate EventHandler e avrà come tipo di ritorno il medesimo tipo del delegate. Un'altra pressione del tasto TAB aggiunge automaticamente, all'interno della classe, il metodo che sarà richiamato quando si genera l'evento in questione:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Gli argomenti di questo metodo sono due: Object sender rappresenta l'oggetto (il controllo, la classe) che ha generato l'evento, ed è utile nel caso in cui la stessa routine venga eseguita in risposta ad eventi lanciati da oggetti diversi, per sapere chi effettivamente lo ha generato; EventAgrs e. EventArgs, come pure tutte le classi da essa derivate, contiene gli argomenti associati all'evento. Nel nostro caso «e» è di tipo EventArgs, ma, può essere specializzata a seconda dell'evento. Ad esempio, nel caso di eventi di gestione del mouse (MouseClick,MouseMove, etc.), è di tipo «MouseEventArgs» e permette di conoscere la posizione del cursore o quale tasto del mouse è stato premuto. Proviamo ad utilizzare la routine Form1_Load. Vogliamo fare in modo che, all'avvio del programma, venga visualizzata una MessageBox con la scritta "Ciao Mondo!". A tal scopo, è sufficiente definire il metodo Form1_Load nel modo seguente:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Eseguiamo ora l'applicazione facendo clic sul pulsante Figura 2: L'output del programma Gli event handler possono essere creati anche in un altro modo. All'interno della finestra di progettazione, selezionare il controllo per cui si vuole definire il gestore, quindi spostarsi nella finestra Properties (Proprietà) e fare clic sull'icona raffigurante un fulmine. Comparirà un elenco contenente tutti gli eventi generati dal controllo in questione. Selezionandone uno, nella parte bassa della finestra sarà visualizzato un breve messaggio che indica quando tale evento viene lanciato. Clicchiamo su un evento, digitiamo il nome di una routine nella casella di testo corrispondente e premiamo il tasto INVIO, Visual Studio aggiungerà automaticamente il codice per installare l'event handler (all'interno del file del Designer) ed inserirà nel file del form una routine con il nome indicato. In alternativa, facendo doppio clic sul nome dell'evento, sarà creato un event handler e una routine di gestione con il nome predefinito (formato da nome del controllo, trattino basso e nome dell'evento). Per eliminare un gestore degli eventi creato in questo modo, fare clic con il tasto destro del mouse sull'evento e selezionare il comando Reset (Annulla). Infine, per tornare alla visualizzazione delle proprietà del controllo, premere il pulsante Properties (Proprietà) che si trova a sinistra dell'icona con il fulmine. Figura 3: La finestra per la definizione degli event handler Ancora, facendo doppio clic su di un oggetto, Visual Studio definirà automaticamente un event handler per l'evento predefinito dell'oggetto in questione (Load per i form, Click per i pulsanti, TextChanged per le caselle di testo, ecc.). L'esempio che abbiamo realizzato può essere scaricato cliccando Perfavore,
Entra
oppure
Registrati
per vedere i Link!
Questa rapida panoramica sulla Windows Form ha lo scopo di fornire le conoscenze di base che permettano di approfondire l'argomento senza troppa fatica. Per una discussione più dettagliata, si rimanda ai riferimenti a fondo pagina alla guida a VB.NET: nonostante il linguaggio sia differente, i concetti esposti risultano validi anche per C#.
Sono gli oggetti più comuni a tutte le interfacce grafiche come bottoni, checkbox, etc., ma troviamo anche controlli per la gestione di dati o per il dialogo con le periferiche. Tutti impacchettati in classi con metodi e proprietà che ne permettono la personalizzazione a seconda delle esigenze, i controlli consentonto di realizzare applicazioni dall'aspetto professionale con uno sforzo minimo. Dato il loro numero (più di 60), è impossibile analizzarli tutti in questa sede: ci limiteremo a mostrare quali sono le novità dei principali controlli del Framework 2.0, rimandando alla guida su VB.NET (ed alla guida in linea di Visual Studio) per maggiori dettagli sugli altri oggetti. All'interno della Casella degli strumenti di Visual Studio 2005 (Toolbox in inglese), i controlli sono divisi in categorie: All Windows Forms: che visualizza in un'unica scheda tutti i controlli disponibili; Common Controls, che contiene gli oggetti tipicamente presenti in ogni finestra (Label, TextBox, Button, ListBox, ComboBox, etc.); Containers, che raggruppa i controlli che permettono di gestire il layout del form, ovvero la disposizione degli oggetti; menù & Toolbars, contenente oggetti che permettono di aggiungere barre dei menù, barre degli strumenti, barra di stato e menù contestuali all'applicazione; Data, che contiene gli strumenti che permettono di lavorare con fonti di dati esterne (come i database); Components, che raggruppa oggetti i quali consentono di interagire con il sistema operativo (per gestire le Active Directory ed il registro eventi di Windows, monitorare le modifiche al file system, etc.); Printing, che contiene gli oggetti necessari per aggiungere le funzionalità di stampa all'applicazione; Dialogs, contenente i controlli che consentono di visualizzare le finestre di dialogo comuni di Windows, come Apri e Salva con nome. Figura 1. Toolbox di Visual Studio 2005 Controlli come TextBox, ListBox e PictureBox sono stati aggiornati con l'aggiunta di alcune proprietà e funzioni, ma il loro utilizzo è rimasto essenzialmente uguale rispetto alle versioni precedenti di .NET . I controlli MenuStrip (barra dei menù) e ToolStrip (barra degli strumenti), sono stati notevolmente potenziati e supportano lo stile introdotto con Office 2003: Figura 2. Nuovo stile per barra menù e strumenti Essi sostituiscono i vecchi controlli MainMenu e ToolBar. Al loro interno è ora possibile inserire un numero maggiori di elementi: un menù, infatti, può contenere anche TextBox e ComboBox, così come la barra degli strumenti, che è in grado di ospitare anche ProgressBar. Il MenuStrip, inoltre, consente di associare icone alle voci di menù. Anche il controllo StatusStrip, sostituto del vecchio StatusBar ed utilizzato per visualizzare una barra di stato nell'applicazione, ha subito le stesse operazioni di aggiornamento. Un'altra novità è rappresentata dai controlli per gestire il layout della finestra, contenuti nella sezione Containers della «Casella degli strumenti». Accanto ai controlli già presenti nelle versioni del Framework, infatti, sono stati inseriti oggetti come FlowLayoutPanel e tableLayoutPanel, che consentono di disporre automaticamente i controlli inseriti al loro interno. Mostriamo ora un semplice esempio d'uso di alcuni controlli realizzando una piccola applicazione per Windows: un visualizzatore di immagini minimale, composto da una casella di testo in cui digitare il percorso del file, un pulsante per visualizzare la finestra di dialogo «Apri» e un pulsante che mostra l'immagine selezionata in una PictureBox. Una CheckBox permetterà di stabilire se si vuole visualizzare l'immagine nelle sue dimensioni reali oppure ingrandita a occupare tutta l'area disponibile. Figura 3. Interfaccia della applicazione esempio Cliccare Perfavore,
Entra
oppure
Registrati
per vedere i Link!
per scaricare il progetto.Non ci resta che scrivere il codice da associare agli eventi dei controlli. Anziutto vogliamo che, cliccando sul pulsante btnSfoglia, si apra la finestra di esplorazione per selezionare un'immagine. Per associare automaticamente un Event Handler all'evento principale di un determinato oggetto, è sufficiente un doppio click sull'oggetto in questione. Nel nostro caso definiamo l'event handler per l'evento «Click» del pulsante. Nella finestra del codice appare la definizione del metodo delegato e possiamo aggiungere il codice di gestione dell'evento:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
La routine restituisce un valore di tipo DialogResult che permette di conoscere il motivo della chiusura della finestra: DialogResult.OK indica che la finestra è stata chiusa perché l'utente ha premuto il pulsante «OK» (se viene premuto «Annulla», il valore restituito è DialogResult.Cancel). Il nome del file selezionato è salvato nella proprietà FileName del controllo. Ora dobbiamo visualizzare l'immagine selezionata. Facciamo doppio clic sul pulsante «bntVisualizza» e scriviamo questa semplice istruzione:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Ci resta solo da definire il comportamento dell'applicazione sul click del pulsante con chkAdattaImmagine spuntata:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Queste istruzioni fanno sì che, quando la casella è selezionata, ovvero la proprietà «Checked» vale true, la proprietà «sizeMode» della PictureBox venga imposta su PictureBoxsizeMode.StretchImage, in modo che l'immagine si adatta all'area disponibile. La nostra applicazione è pronta. Possiamo eseguirla premendo il tasto F5 per verificare che il suo comportamento sia quello desiderato. L'esempio completo è disponibile per il download cliccando qui. A causa di un bug della versione Beta 2 di Visual Studio 2005 e del Framework .NET 2.0, cambiando la proprietà sizeMode a tempo di esecuzione, l'altezza del controllo PictureBox diminuisce; tale comportamento può essere ignorato, poiché verrà sicuramente risolto con la versione definitiva del Framework .NET 2.0, e comunque è facilmente aggirabile facendo in modo che, ogni volta che si cambia la proprietà sizeMode, la dimensione del controllo venga reimpostata sul valore iniziale.
Gli errori nel mondo .NET, nella migliore tradizione Object Oriented (Java, C++, etc.) vengono rappresentati con le eccezioni: una intera gerarchia di classi per la gestione degli eventi indesiderati. Le eccezioni vengono "sollevate" al verificarsi di una situazione anomala, come un errore. Si possono ignorare, con il rischio di avere delle brutte sorprese a run-time, oppure si possono intercettare e gestire. Questo implica l'uso di un costrutto nato appositamente per l'intercettazione delle eccezioni: try-catch-finally.
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Nel costrutto try-catch è necessario specificare almeno una clausola catch oppure una finally; si possono indicare più catch, una per ogni tipo di errore che si vuole gestire, mentre è consentito inserire solo una clausola finally. Nella clausola catch si può indicare il tipo di eccezione che si vuole gestire; ad esempio:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
In entrambi i casi, l'oggetto «ex» contiene varie informazioni sull'errore. Ad esempio, la proprietà ex.Message restituisce una stringa di descrizione della causa dell'eccezione. Aggiorniamo ora l'applicazione che abbiamo realizzato nella lezione precedente aggiungendo la gestione degli errori. In particolare, consideriamo l'istruzione
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Ogni volta che, cercando di caricare un file, si verifica un'eccezione di tipo «FileNotFoundException», viene eseguito il blocco catch corrispondente, il quale visualizza una finestra di messaggio. L'errore di file non trovato, però, non è l'unico che può capitare quando si cerca di aprire un file: ad esempio, se la memoria a disposizione non è sufficiente per completare il caricamento, si ottiene un errore di tipo OutOfMemoryException. Ancora, se si preme il pulsante «Visualizza» senza aver digitato alcun nome di file, si verifica una ArgumentException. Aggiungiamo, quindi, un secondo blocco catch per trattare tutti gli altri casi, ottenendo complessivamente:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
In questo caso abbiamo usato l'informazione contenuta nell'eccezione «ex» per sapere con esattezza l'origine dell'errore. L'esempio completo è disponibile Perfavore,
Entra
oppure
Registrati
per vedere i Link!
È sempre meglio evitare la gestione delle eccezioni, cercando di prevedere, dove possibile, le cause che possono portare ad una situazione imprevista: un abuso di try...catch, infatti, può appesantire molto un programma. Nel nostra applicazione, ad esempio, l'errore ArgumentException può sempre essere evitato semplicemente facendo in modo che il metodo FromFile venga richiamato solo se è stato digitato qualcosa nella casella di testo.
I mondi delle applicazioni desktop e delle applicazioni web convergono con .NET. È stato introdotto un modello di programmazione per il Web che ha permesso ai programmatori VB e C# di trasferire le proprie competenze di sviluppo Windows in ambito Web e viceversa. Per realizzare ed eseguire un'applicazione Web con ASP .NET è necessario che nel sistema sia installato il framework .NET ed un web server in grado di interpretare ed eseguire i file ASP .NET, che hanno estensione .aspx. Visual Studio 2005 include un tool di sviluppo Web completamente rinnovato, Visual Web Developer, che integra un piccolo server Web per consentire a tutti di sperimentare da subito le potenzialità di ASP .NET. ASP.NET fornisce un ambiente orientato agli oggetti e basato sugli eventi per le applicazioni Web. Le pagine non sono altro che classi C# o VB.NET con le caratteristiche che abbiamo già introdotto. Esse ereditano le funzionalità di base dalla classe «Page» come una Windows Form eredita dalla classe «Form». Realizziamo una prima applicazione Web con Visual Studio 2005. Ne approfitteremo per introdurre i primi concetti relativi alla gestione delle pagine ASP.NET . Dopo aver avviato l'ambiente di sviluppo, selezioniamo dal menù File>new e clicchiamo sulla voce «Web Site» (Sito Web). Appare una finestra di dialogo: Figura 1. La finestra di dialogo New Web Site Scegliamo «ASP .NET Web Site», quindi, nella parte bassa della finestra, indichiamo che la locazione del sito è il file system (le altre opzioni sono HTTP e FTP) e che il linguaggio utilizzato è C#. clicchiamo su «OK» e Visual Studio crea una soluzione contenente un file di nome «Default.aspx» (la pagina iniziale del sito) e uno contenente il cosiddetto code behind della pagina, chiamato «Default.aspx.cs». Questa caratteristica è molto importante: tutto il codice degli script della pagina, che in genere è "immerso" all'interno dell'HTML, ora può risiedere anche in un file separato, consentendo una separazione tra grafica e codice. Figura 2. Il Solution Explorer di Visual Web Developer Cliccando con il pulsante destro su «Default.aspx» e selezionando «View Designer» (Visualizza Progettazione) si apre l'editor visuale della pagina Web. La casella degli strumenti sulla sinistra ospita un gran numero di controlli divisi in varie categorie. Per il momento ci interessano quelli che si trovano nella categoria Standard, la quale contiene una serie di controlli simili a quelli per le applicazioni desktop. Figura 3. La toolbox di Visual Web Developer Con un doppio clic sul controllo «Label», inseriamo nella pagina un'etichetta; sulla destra, nella finestra «Properties», saranno visualizzate le proprietà dell'oggetto, le modifichiamo come indicato di seguito (la proprietà ID corrisponde alla proprietà Name dei controlli Windows):
HTML:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Proviamo ad eseguire l'applicazione ASP .NET finora realizzata. Il progetto si avvia come se si trattasse di un'applicazione Windows, quindi premendo il tasto F5 oppure il pulsante sulla barra degli strumenti. La prima volta che l'applicazione viene lanciata comparirà una finestra che chiede se si vuole attivare il debug per il sito Web, selezioniamo l'opzione Add new Web.config file with debugging enabled e confermiamo con «OK»: fatto ciò, verrà avviato il server Web integrato in Visual Web Developer e l'applicazione ASP .NET sarà visualizzata all'interno del browser Web predefinito. Nel caso in cui abbiamo un progetto composto da più pagine, per scegliere quale mostrare nel browser è sufficiente selezionarla nel Solution Explorer prima di avviare l'esecuzione (non è necessario impostarla come pagina di avvio, come si doveva fare con le precedenti versioni di Visual Studio). Per il momento, l'unica cosa che appare nella pagina è la stringa "Ora di connessione", come si trattasse di una pagina statica. Chiudiamo il browser e torniamo in Visual Studio per aggiungere una prima componente dinamica. Con un doppio clic su un punto vuoto della pagina all'interno dell'editor aggingiamo automaticamente il gestore dell'evento Load, che viene inserito nel "code behind" della pagina ovvero nel file «Default.aspx.cs».
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Figura 4. Esecuzione del programma L'esempio realizzato può essere scaricato cliccando Perfavore,
Entra
oppure
Registrati
per vedere i Link!
Con Visual Web Developer è possibile costruire graficamente una Web Form proprio come si fa con la Windows Form, utilizzando controlli simili per aspetto e proprietà: è poi l'editor che, in modo del tutto automatico, si preoccupa di produrre "dietro le quinte" il codice HTML necessario per visualizzare gli elementi dell'interfaccia all'interno del browser Web. Scendendo nei dettagli dell'implementazione, una Web Form è una pagina Web in cui tutti gli elementi (testo, elenchi, pulsanti, caselle, ecc.) sono inseriti all'interno di una normale form HTML, ovvero tra i tag <form> e </form>. Per leggere il codice HTML è sufficiente fare clic sul pulsante «Source» (Sorgente) visualizzato nella parte bassa del Designer. Figura 1. Modalità di visualizzazione di una pagina ASP .NET Anche la Web Form è un oggetto al pari di tutti gli elementi in essa contenuti, per cui è possibile accedere a metodi e proprietà. Inoltre dal codice di una pagina è possibile accedere all'intera libreria di classi di .NET . Abbiamo già visto un esempio di come utilizzare la classe DateTime per recuperare la data e l'ora di sistema. PostBack Quando la pagina viene caricata all'interno del browser, viene generato l'evento Page_Load. Nel codice del delegato per Page_Load è possibile verificare se l'utente sta effettuando il primo accesso alla pagina oppure sta effettuando un PostBack. La tecnica del postback è quella che consente ad una pagina Web di trasmettere a se stessa delle informazioni di stato. In pratica in una pagina web dinamica viene creato un form che ha come campo «action» l'indirizzo della pagina stessa ed al suo interno dei campi «hidden» che mantengono informazioni sullo stato della pagina. Per esempio potremmo avere un campo che contiene il testo di una casella di testo. Molto spesso vengono usati campi «hidden» per ricordare se includere una porzione di codice o meno. Queste informazioni una volta generato un evento "Submit" (che non necessariamente scaturisce da un bottone), vengono "rispedite indietro" alla pagina che le usa per modificare il suo aspetto. Questa tecnica è abbastanza comune per chi programma in ASP o PHP, ma ASP.NET l'ha intergata nel concetto di Web Form con il PostBack e il ViewState che vedremo tra breve La proprietà IsPostBack restituisce il valore true quando il modulo presente nella pagina è stato eseguito, false quando si tratta del primo accesso alla pagina:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Esempio Realizziamo ora una piccola applicazione Web. Vogliamo fare in modo che l'utente possa digitare il suo nome e, premendo un pulsante, riceva un messaggio di saluto. Usiamo i controlli della categoria Standard della Toolbox. Per aggiungere un oggetto alla Web Form è sufficiente fare doppio clic su di esso nella casella degli strumenti, una volta inserito può essere spostato utilizzando il mouse, come si fa per i Controlli Windows. Posizioniamo così la Label lblNome. trattandosi di un normale form HTML, inoltre, è possibile scrivere direttamente del testo all'interno della pagina. La Web Form dovrebbe risultare simile a quella visibile in figura. Figura 2. Il layout della pagina Impostiamo le proprietà degli oggetti come indicato nella tabella seguente:
HTML:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Cliccare Perfavore,
Entra
oppure
Registrati
per vedere i Link!
per scaricare la pagina.Visualizziamo il sorgente ed analizziamo il codice della pagina. Osserviamo che al pulsante «Conferma» è associata la riga:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Aggiungiamo il delegato per la pressione del bottone. Torniamo in modalità Design e facciamo doppio clic sul bottone per definire l'event handler corrispondente al «Click». L'ide ci mostrerà il file con il "code behind" della pagina ed avrà preparato per noi la dichiarazione del delagato. A questo punto è sufficiente scrivere:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
In questo modo si istruisce il server che, alla pressione del pulsante, quando verrà eseguito il PostBack della pagina, deve essere richiamato il metodo btnConferma_Click contenuto nel code behind. La nostra applicazione è pronta per l'esecuzione. Avviamola, digitiamo un nome nella casella di testo e premiamo il pulsante. Otteniamo: Figura 3. L'output del programma Cliccare Perfavore,
Entra
oppure
Registrati
per vedere i Link!
per scaricare l'esempio.Proviamo a visualizzare il sorgente della pagina all'interno del browser Web (ad esempio, in IExplorer, con il comando Visualizza>HTML), notiamo che tutto il codice ASP .NET è stato tradotto in HTML standard. Non c'è però traccia del codice dello script. Esso, in modo del tutto invisibile, è stato compilato in una libreria che risiede sul server e che viene richiamata ogni volta che si effettua il post della pagina (abbiamo infatti detto che una Web Form è un particolare tipo di form HTML). Viewstate Continuando ad osservare il sorgente, notiamo che nella form è stato inserito anche un campo nascosto di nome __VIEWSTATE, che può apparire nel modo seguente:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
HTTP è un protocollo stateless (senza stato), ovvero non mantiene informazioni sullo stato di una pagina tra una visita e l'altra: per sopperire a tale mancanza, ASP .NET utilizza il campo ViewState. Ogni volta che si ricarica una pagina, i controlli in essa presenti vengono inizializzati sulla base del contenuto del ViewState, che viene generato automaticamente da ASP .NET . Questa soluzione consente di trasferire lo stato dei controlli dal server al client e viceversa. Ciò significa che quando il server leggerà il ViewState di una pagina sarà in grado di ripristinare, ad esempio, il valore corrente di tutti i campi «input», senza bisogno che sia il programmatore a farlo via codice. trattandosi di una tabella associativa, inoltre, nel ViewState è possibile inserire anche dei valori personalizzati. Ad esempio, possiamo memorizzare nel ViewState il numero di volte in cui il pulsante Conferma è stato premuto:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
È possibile scaricare la nuova versione della pagina Perfavore,
Entra
oppure
Registrati
per vedere i Link!
Il ViewState è mantenuto solo se vengono eseguite richieste consecutive della stessa pagina: nel caso in cui venga caricata una nuova pagina, il ViewState sarà perso. Per mantenere le informazioni durante la navigazione, è possibile ricorrere all'oggetto Session. Anch'esso si comporta come una tabella associativa e funziona esattamente come il ViewState, tuttavia le variabili archiviate al suo interno non vengono cancellate quando l'utente passa da una pagina a un'altra dell'applicazione, ma sono mantenute per tutta la "sessione" che inizia quando un browser punta al nostro sito e finisce quando viene chiusa.
Al pari dei controlli Windows, anche i controoli Web sono raggruppati in categorie nella Casella degli strumenti. In questa guida ci limiteremo a parlare dei controlli della categoria Standard, che comprende, tra gli altri: Label, TextBox, Button (che abbiamo già incontrato); DropDownList, ListBox; CheckBox, RadioButton; CheckButtonList, RadioButtonList, che consentono di raggruppare, rispettivamente, un insieme di CheckBox oppure di RadioButton; Image, ImageMap, ImageButton; table. Figura 1. Toolbox di Visual Web Developer Come al solito ci aiuteremo con un esempio pratico. Realizziamo una Web Form in cui inserire i propri dati personali, che verranno poi inviati ad un indirizzo di posta elettronica. Dopo aver creato un nuovo progetto Web, aggiungiamo i controlli alla Web Form in modo da ottenere un'interfaccia analoga a quella visibile in figura: Figura 2. Il layout della pagina Le proprietà degli oggetti sono riassunte nella tabella seguente:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
È possibile scaricare Perfavore,
Entra
oppure
Registrati
per vedere i Link!
la Web Form creata finora.Passiamo alla scrittura del codice. Selezionando l'ultima voce della lista che contiene gli hobbies, vogliamo che appaia la casella di testo in cui digitare il nome del passatempo. Allo stesso modo, se si clicca su un'altra opzione, questa TextBox deve essere nascosta. Clicchiamo due volte sul controllo «lstHobby» per definire l'event handler predefinito, ovvero SelectedIndexChanged, quindi scriviamo:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
La form si comporta in questo modo perché abbiamo impostato la proprietà AutoPostBack della ListBox su true. Infatti AutopostBack è a true qualunque evento il controllo scateni viene provocato un Submit() ovvero in PostBack e viene ricaricata la pagina. In questo caso, ogni volta che si seleziona un elemento diverso della lista viene effettuata una richiesta al server, il quale esegue il codice corrispondente all'evento SelectedIndexChanged. Lasciando tale proprietà su false (valore predefinito) invece il PostBack viene causato da un altro evento, tipicamente la pressione di un bottone. Talvolta, per forzare l'invio anche in seguito ad altre azioni, si ricorre a codice JavaScript introducento una chiamata a Submit(). Anche ASP .NET usa questo metodo, ma lo "nasconde" nella proprietà AutoPostBack: quando vale true, tra i tag del controllo viene automaticamente aggiunta una chiamata a Submit() Per verifica impostiamo la proprietà AutoPostBack del controllo «lstHobby» su false ed eseguiamo nuovamente l'applicazione. Questa volta, la selezione degli elementi non determina una richiesta al server. L'evento SelectedIndexChanged sarà generato solo in seguito alla pressione del pulsante Invia. Aggiungiamo il codice da eseguire sul «Click» del pulsante, che deve inviare via mail le informazioni inserite nella Web Form:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Per scaricare la Web Form completa, cliccare Perfavore,
Entra
oppure
Registrati
per vedere i Link!
Sono disponibili anche dei controlli per la verifica degli input degli utenti. Si usano come tutti i controlli e permettono, ad esempio, la verifica che il nome e l'indirizzo di mail siano stati effettivamente digitati ed il formato degli indirizzi.
In alcune situazioni, tuttavia, potrebbero essere necessari oggetti più sofisticati di quelli predefiniti: in questo caso possiamo creare un Web User Control (Controllo utente), utilizzando le stesse tecniche introdotte nelle scorse lezioni. In effetti, un Web Control può essere costruito come una Web Form: anch'esso è dotato di un'interfaccia utente e di un file con il code behind; a differenza di una Web Form, tuttavia, è contenuto in un file con estensione ".ascx" e non può avere i tag <HTML>, <BODY> e <FORM> poiché viene inserito in una Web Form che questi tag li contiene già. Anche un Web User Control è una classe ed eredita le sue funzionalità di base da System.Web.UI.UserControl. Per definire un Web User Control, dopo aver creato un nuovo sito ASP .NET facciamo clic con il tasto destro del mouse sul nome del progetto all'interno del Solution Explorer e selezioniamo il comando «Add New Item...» (Aggiungi nuovo elemento). Si aprirà una finestra di dialogo in cui sono mostrati tutti i tipi di file che possono essere aggiunti. Selezioniamo «Web User Control» e impostiamo il nome del file e il linguaggio in cui scrivere il code behind. Grazie al runtime comune del Framework .NET è possibile avere una Web Form scritta in C# al cui interno si trova un Web Control realizzato con Visual Basic .NET, e viceversa. Figura 1. La finestra di dialogo Add New Item Confermiamo premendo il pulsante «Add» (Aggiungi). Il nuovo Web Control sarà al aggiunto progetto, insieme al file contenente il code behind. A questo punto si aprirà automaticamente la visualizzazione della pagina sorgente. Passando al Designer, ci troviamo di fronte allo stesso editor visuale con cui si creano le Web Form. Creiamo un semplice controllo composto da una Label e da una TextBox visto che questi due elementi sono spesso utilizzati in coppia, avere un Web Control che li definisce entrambi in una sola volta permette di risparmiare tempo nella creazione delle pagine. L'interfaccia dovrebbe risultare come la seguente: Figura 2. Il layout del Web User Control L'impostazione delle proprietà è semplice:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Perfavore,
Entra
oppure
Registrati
per vedere i Link!
per scaricare il controllo.Aggiungiamo le proprietà che consentono di lavorare con l'etichetta e la casella di testo. Dal momento che il Web Control, una volta inserito in una pagina ASP .NET, viene visto come un unico oggetto, deve disporre di proprietà che permettano di modificare gli oggetti contenuti al suo interno. Nel file del code behind definiamo le proprietà Caption e Text, per leggere e cambiare, rispettivamente, il testo dell'etichetta e il contenuto della casella:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Aggiungiamo questo controllo ad una pagina ASP .NET. Visualizziamo la Web Form in cui inserire l'oggetto, quindi, all'interno del Solution Explorer, clicchiamo sul nome del Web Control (il nome predefinito è WebUserControl.ascx). trasciniamolo nella posizione desiderata della pagina: una volta rilasciato il mouse, il nostro Web User Control sarà visualizzato. La finestra delle proprietà dell'oggetto dovrebbe mostrare anche le proprietà che abbiamo definito in precedenza; se così non fosse, è sufficiente chiudere la pagina, salvare il controllo e riaprirla. I valori di Caption e di Text possono essere impostati sia in fase di progettazione, utilizzando la finestra delle proprietà, sia da codice, ad esempio:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Se ora diamo uno sguardo al sorgente della Web Form, notiamo che, quando si aggiunge un Web Control ad una pagina, in essa viene inserita la direttiva @Register: si tratta di una sorta di "include" e specifica che nella pagina si utilizza un controllo il cui codice è contenuto in un file esterno. Cliccare Perfavore,
Entra
oppure
Registrati
per vedere i Link!
per scaricare un esempio di utilizzo del controllo all'interno di una Web Form.
La differenza principale tra i due tipi di controlli riguarda la fase di progettazione e consiste nella semplicità di creazione da una parte e nella facilità d'uso dall'altra. I controlli Web sono semplici da creare, dal momento che si realizzano in maniera visuale, dispongono del code behind e supportano la gestione degli eventi. Tuttavia, un Web User Control non può essere aggiunto alla Casella degli strumenti ed è rappresentato in maniera statica quando viene aggiunto ad un pagina (ovvero la modifica di una sua proprietà non si riflette nelle visualizzazione all'interno del Designer, ma è visibile solo in fase di esecuzione). Inoltre, l'unico modo di condividere il controllo tra applicazioni diverse consiste nell'inserirne una copia distinta in ciascun progetto, soluzione che richiede una maggiore gestione nel caso in cui si apportino modifiche al controllo. Una Web Control Library invece in genere si realizza scrivendo a mano il codice che poi sarà compilato. Dunque è più difficile da realizzare. Una volta realizzato il controllo, tuttavia, è possibile aggiungerlo alla Casella degli strumenti e gestirlo in modo analogo a quanto visto per i controlli standard. Proviamo a creare una Web Control Library, cercando di analizzare le caratteristiche principali di questo tipo di controlli. Dopo aver creato un sito ASP .NET, aggiungiamo un progetto alla soluzione e selezioniamo come tipo di progetto "Web Control Library", come evidenziato in figura. Figura 1. La finestra di dialogo Add Project L'editor di Visual Studio aprirà automaticamente il file "WebCustomControl1.cs". Analizziamo il codice inserito di default nel file (alcune parti sono state omesse per motivi di spazio):
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Alla dichiarazione della classe ed alla proprietà "Text" sono stati aggiunti, tra parentesi quadre, i cosiddetti Custom Attributes, ovvero una serie di attributi che forniscono informazioni aggiuntive sulle classi, sui metodi e sulle proprietà. Ad esempio, ToolboxData indica quale tag è associato al controllo: in pratica, quando tale controllo sarà inserito in una pagina, esso sarà identificato dal tag specificato in questo attributo. Ancora, Category specifica la categoria in cui sarà visualizzata la proprietà Text all'interno della visualizzazione per categorie della finestra Properties. Un'analisi dettagliata dei Custom Attributes esula dagli obiettivi di questo corso, per cui si rimanda alla guida in linea. Concentriamoci invece sul metodo Render(), il "cuore" del Web Control: esso, infatti, specifica qual è il codice HTML che deve essere inserito nella pagina per visualizzare il controllo. Questa routine riceve come argomento un oggetto di tipo HtmlTextWriter su cui scrivere il codice HTML. Senza scendere nei dettagli, il metodo Render() viene automaticamente richiamato dal runtime del Framework sia quando il controllo è visualizzato in una pagina ASP .NET nel Visual Web Developer, sia quando deve essere generato il contenuto HTML da inviare al browser. Nel primo caso, output rappresenta la pagina all'interno dell'editor, nel secondo si riferisce alla pagina che viene inviata al client per la visualizzazione nel browser (in pratica, il codice HTML che viene scritto dal metodo Render() è il codice che l'utente riceve quando richiede la pagina al server). Anche i controlli Web standard si comportano nello stesso modo: ogni controllo inserito in una pagina genera il codice HTML necessario alla sua visualizzazione tramite il metodo Render(). Ad esempio, la routine Render() di un controllo Label produce il seguente codice HTML:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Anzitutto dobbiamo compilare il file DLL che sarà utilizzato dall'applicazione ASP .NET. Dopo esserci assicurati che il progetto selezionato nel Solution Explorer sia "WebControlLibrary1", clicchiamo su comando Build>Build ebControlLibrary1. Ora apriamo il file "Default.aspx" in visualizzazione design. La Toolbox si è arricchita di una nuova scheda che corrisponde alla nostra Web Control Library: essa contiene una voce per ogni classe che estende WebControl contenuta al suo interno: ognuna di esse, infatti, rappresenta un oggetto che può essere inserito nella pagina. Per il momento c'è solo WebCustomControl1. Figura 2. La Toolbox con il nuovo controllo Web Aggiungiamo il nostro contollo alla pagina e, nella finestra delle proprietà, modifichiamo il valore di Text: a differenza di quanto avviene con i Web User Control, la modifica si riflette anche in fase di progettazione. Eseguiamo l'applicazione e verifichiamo il risultato nel browser. Ora modifichiamo il controllo perchè il testo specificato appaia automaticamente in grassetto. Ricordando quanro detto in precedenza, è sufficiente modificare il codice HTML generato dal controllo, ovvero intervenire sul suo metodo Render(). Poichè il metodo Write() dell'oggetto HtmlTextWriter si limita a scrivere sulla pagina tutto quello che riceve come argomento, un primo modo per fare quello che vogliamo potrebbe essere inserire tutto in un'unica istruzione:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Possiamo invece usare altri metodi messi a disposizione da HtmlTextWriter per produrre codice più leggibile e con una distinzione maggiore tra tag HTML e contenuto vero e proprio:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
In alternativa a queste due istruzioni, avremmo potuto usare semplicemente:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Visualizzando il sorgente HTML della pagina nel browser, notiamo che il testo specificato nella proprietà Text del controllo è stato inserito tra i tag <b> e </b>. È possibile scaricare tutto il codice che abbiamo realizzato cliccando . Anche questi controlli, come i controlli Web utente, una volta inseriti in una pagina prevedono l'uso della clausola @ Register associata. Continuiamo a parlare della Web Control Library e vediamo come creare controlli personalizzati estendendo gli oggetti esistenti. Realizziamo il controllo che abbiamo creato con la tecnica Web User Control (Label+TextBox), costruendolo esclusivamente via codice. Questa soluzione ci permetterà di definire un controllo con layout dinamico, cosa che non è possibile fare utilizzando i Web User Control. Riprendiamo la soluzione creata nella lezione precedente e aggiungiamo un nuovo Custom Control. Clicchiamo col tasto destro del mouse sul nome del progetto «WebControlLibrary1» nel Solution Explorer e selezioniamo il comando Add quindi «New Item...» (Nuovo elemento). Nella finestra di dialogo che appare è già selezionato l'elemento «Web Custom Control». Diamogli il nome «LabelTextBox» e clicchiamo su Add. Figura 1. La finestra di dialogo Add New Item Questa volta il codice di default di Visual Studio è superfluo per i nostri scopi: eliminiamo la proprietà «Text», la variabile privata «text» e il corpo del metodo Render(). Volendo realizzare una casella di testo con una caratteristica in più rispetto a quella predefinita, facciamo in modo che il nostro nuovo controllo estenda la classe TextBox invece del generico WebControl: così facendo, esso disporrà automaticamente di tutte le proprietà, i metodi e gli eventi della TextBox.
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Inseriamo anche una proprietà che consente di specificare se l'etichetta deve essere visualizzata a fianco oppure sopra la casella di testo: in questo modo il nostro controllo avrà un layout dinamico, ovvero un layout variabile a seconda dell'impostazione delle sue proprietà:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Side, per mostrarla a fianco della casella di testo, Over, perché sia inserita al di sopra della casella di testo. Infine, nel metodo Render() scriviamo le istruzioni che producono il codice HTML per la visualizzazione del controllo:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Compiliamo la Web Control Library e visualizziamo nel Designer la pagina «Default.aspx». Alla Toolbox è stato automaticamente aggiunto il nuovo controllo: clicchiamo due volte sulla voce LabelTextBox per inserirlo nella pagina. Figura 2. Il nuovo controllo nella Toolbox Le proprietà di cui dispone sono tutte quelle della classica TextBox, più le due che abbiamo definito. Figura 3. Le nuove proprietà del controllo Proviamo a modificare CaptionPosition: il suo cambiamento produce immediatamente un nuovo layout per il controllo. Figura 4. I due layout del controllo Ereditando da TextBox il nostro controllo espone tutti gli eventi tipici dell'oggetto base. Ad esempio, cliccando due volte su di esso, nel code behind sarà automaticamente aggiunto l'event handler per l'evento TextChanged. Cliccare Perfavore,
Entra
oppure
Registrati
per vedere i Link!
per scaricare il codice sorgente del controllo LabelTextBox insieme con una Web Form che ne mostra l'utilizzo.
È possibile avere un file «Web.config» diverso in ciascuna directory del sito: ognuno di essi applica le impostazioni di configurazione sulla propria directory e su tutte le sottodirectory. I file di configurazione nelle sottodirectory possono stabilire configurazioni aggiuntive a quelle ereditate dalle directory padre oppure possono sostituire o modificare quelle definite nei livelli superiori. Un file Web.config può contenere vari tipi di informazioni: variabili comuni a tutte le pagine; configurazioni per le sessioni; opzioni per la gestione degli errori; informazioni per la sicurezza. Abbiamo già accennato al file Web.config in precedenza, quando lo abbiamo aggiunto al progetto per attivare il debug dell'applicazione. Apriamo uno qualunque dei siti Web che abbiamo realizzato nelle scorse lezioni, cliccando due volte sul file Web.Config all'interno del Solution Explorer si aprirà un file contenente un gran numero di commenti, inseriti automaticamente allo scopo di facilitare la modifica delle opzioni. In effetti, prima della versione 2.0 del Framework .NET, il file Web.config poteva essere modificato esclusivamente con un editor di testi; non esisteva alcuno strumento visuale di editing, per cui i commenti erano fondamentali. ASP .NET 2.0, invece, fornisce anche uno strumento grafico per la configurazione che si basa su un'interfaccia Web ed è raggiungibile facendo cliccando su ASP .NET Configuration nel Solution Explorer. Figura 1. ASP .NET Configuration Il file Web.Config è composto da due sezioni fondamentali: appSettings e system.web:
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
Oltre a Web.config, ad un sito ASP .NET può essere aggiunto un file di nome global.asax. Esso risiede nella directory principale del sito ed è una sorta di "contenitore" di codice comune all'applicazione. Viene impiegato, tra l'altro, per: eseguire operazioni all'avvio e al termine delle sessioni e dell'applicazione; eseguire del codice al verificarsi di una condizione di errore. Per inserire il file global.asax ad un progetto, nella finestra di dialogo «Add New Item» è necessario selezionare la voce Global Application Class. Il file che viene aggiunto include già le dichiarazioni per gli event handler che possono essere definiti. I commenti inseriti automaticamente spiegano quando i vari eventi sono generati: ad esempio, al verificarsi di un errore, se questo non viene già intercettato dal codice presente nella pagina con un blocco try-catch, viene scatenato l'evento Application_Error.
Questo, tuttavia, non è l'unico strumento disponibile: tra le alternative, segnaliamo SharpDevelop: si tratta di un IDE per la realizzazione di applicazioni .NET completamente gratuito e distribuito con il codice sorgente. Figura 1. L'ambiente di sviluppo di SharpDevelop Scritto in C#, riproduce abbastanza fedelmente l'ambiente di sviluppo di Visual Studio .NET 2003 (pur non in tutte le funzionalità), supporta le versioni 1.0 e 1.1 del Framework .NET, può compilare utilizzando Mono (di cui parleremo tra breve) e consente di realizzare applicazioni in C#, Visual Basic .NET e C++. Dispone anche di uno strumento per l'importazione/esportazione di progetti di Visual Studio e la traduzione di codice C# in VB .NET e viceversa. Al momento della stesura di questa guida, inoltre, è in fase di realizzazione una nuova release di SharpDevelop, che sarà compatibile con la versione 2.0 del Framework e supporterà le nuove caratteristiche dell'editor di Visual Studio 2005. Lo stesso Framework .NET di Microsoft ha una sua controparte: Mono, un'implementazione open source del Framework che ha come obiettivo primario quello di rendere multipiattaforma le applicazioni .NET. Grazie a Mono è possibile scrivere applicazioni in C#, utilizzando le stesse tecniche che abbiamo analizzato in questa guida, ed eseguirle su piattaforma Linux o Windows. Frutto di un intenso lavoro di sviluppo da parte di Ximian e di una nutrita comunità di sviluppatori di tutto il mondo, Mono si compone di: un compilatore per i linguaggi C# e VB .NET con cui è possibile sviluppare applicazioni compatibili con la piattaforma di Microsoft; un compilatore che consente a Linux di far girare applicazioni scritte sotto un qualsiasi altro sistema operativo che supporti .NET, primo fra tutti Windows; un modulo che aggiunge ad Apache il supporto per ASP .NET; un insieme di librerie che permette lo sviluppo di applicazioni utente e servizi Web in grado di girare sotto vari sistemi operativi. Mono comprende anche l'ambiente di sviluppo MonoDevelop, una macchina virtuale Java ed il supporto a diversi altri linguaggi di script, tra cui Python e JScript. Fra le maggiori lacune che attualmente si riscontrano c'è la mancanza del supporto a COM. In ogni caso, le versioni di Mono si susseguono in maniera costante. Attualmente Mono fornisce un supporto quasi completo della «Base Class Library» di .NET ed integra alcuni dei nuovi controlli introdotti con ASP .NET 2.0. Fonte= Programmazione.Html |