Una delle caratteristiche chiave di WPF, che lo differenzia da architetture alternative come le Windows Form e ASP.NET, consiste nel suo sistema di misura indipendente dalla risoluzione. In altre parole, WPF non utilizza più il PIXEL come unità di misura per indicare la dimensione di un bottone, di un rettangolo o di un video; infatti, il pixel non ha una dimensione standard: ce ne stanno per esempio 96 in un pollice (2,54 cm) per un monitor LCD da 19’’, ma ben 130 in uno schermo di un notebook recente; per rendersi conto di questo serve solo un righello: misurate la larghezza del vostro monitor (33,87 cm nel primo caso, 32,82 nel secondo) e la dividete per la risoluzione orizzontale (1280 nel primo, 1680 nel secondo), otterrete così la larghezza di un pixel in centimetri, che poi potete trasformare in DPI (pixel per pollice) con una semplice equivalenza.
L’immediata conseguenza di indicare le misure in pixel, e questo lo sanno anche i sassi, è che l'interfaccia risulta più grande al diminuire della densità: se cambiate la risoluzione del vostro schermo da 1280x1024 a 800x600 e mantenete uguale l’area visibile vi troverete gli oggetti più grandi del 60% perché di fatto questa è la crescita che ciascun pixel ha avuto; apro e chiudo una parentesi, anche questo tutti lo sanno ma repetita iuvant: i monitor LCD hanno una risoluzione nativa e cambiarla equivale a fare sì che il software del monitor (NON della scheda grafica) riscali la nuova risoluzione su quella nativa, con un peggioramento evidente della qualità; come vedremo più avanti, la strada da seguire per ingrandire l’immagine è agire sui DPI, NON sulla risoluzione.
Ma allora, che unità di misura utilizza WPF? Il millimetro, il centimetro, il pollice, il metro? Fuochino. Nel senso che utilizza un’unità di misura appunto indipendente dalla risoluzione; quindi invece di dire che un bottone è largo 100 pixel, imposta per esempio la sua misura a 2 centimetri; a quel punto, quando l’utente si sposta su un monitor che ha una densità di pixel diversa –come negli esempi sopra- il bottone dovrebbe continuare a misurare 2 centimetri.
Perché dico dovrebbe? Beh, perfino chi ha già sviluppato in WPF -e non si è posto il problema- probabilmente non non ha ancora notato la differenza nel sistema di misura di WPF rispetto agli altri; anzi, avrà notato il contrario: cambiando monitor, anche gli oggetti WPF cambiano di dimensione; addirittura, rimanendo sullo stesso monitor e cambiando risoluzione, le applicazioni WPF scalano esattamente come le Windows Forms e le applicazioni WEB. Spiegherò il perché di tutto questo fra un momento.
Lasciatemi prima dire, anche se è un dettaglio, qual è l’unità di misura indipendente dalla risoluzione (che di seguito chiamerò DIU: Device Independent Unit) che usa WPF; tenetevi forte: 0,026458333333 centimetri; comodo da ricordare, vero ;-) ? Per avere un’idea più pratica, considerate che è circa un quarto di millimetro. Ma probabilmente la fissiamo meglio in mente se consideriamo che ci sono esattamente 96 DIU ogni 2,54 centimetri. In altre parole 1 DIU = 1/96 di pollice. Quindi se vogliamo fare un bottone largo 1 pollice dovremo indicare Width="96", e ovviamente 10 centimetri misurano 377,95 DIU.
Torniamo all'osservazione di prima: prendo un righello, lancio Visual Studio, metto sulla form WPF un bottone da 96 DIU, lo misuro e... mi accorgo che NON è largo necessariamente un centimetro! Abbasso la risoluzione, diventa più largo, vado su un altro PC e cambia ancora... ma allora dov’è la blasonata RESOLUTION INDEPENDENCE di WPF? Il punto è che WPF si basa sulle impostazioni di sistema, non sulle impostazioni del device fisico (il monitor); se ci pensate un momento, questo ha perfettamente senso: come fa il vostro sistema a sapere quanti centimetri è largo il vostro monitor? Come fa a sapere la distanza del telo dal prioettore collegato alla vostra uscita video, visto che le dimensioni dell’immagine dipendono da questa? Non lo sa. A meno che non siate voi a dirglielo. Come? Fate le misurazioni (vedi l’esempio introduttivo di questo post, dove calcolavo 130 DPI) e specificatele nel Pannello di Controllo (sezione DPI Scaling) come indicato di seguito:
A questo punto impostate Width="377.95" nei parametri del bottone (sì, avete letto bene: i DIU si specificano in double) , prendete il righello e verificate se non ci credete: il bottone è largo 10 centimetri, su qualunque monitor e, naturalmente, anche se lo stampate su una LASER da 1200 DPI o su una ad aghi!
Provate a fare la stessa cosa con un’applicazione tradizionale in finestra o WEB: non si può, o meglio in teoria potreste farlo ma non certo utilizzando un’unica misura (377,95): dovreste contare quanti pixel ci vogliono per fare 10 centimentri e cambiare la dimensione di conseguenza di dispositivo in dispostivo; per curiosità e piacere di calcolo: se impostate Width="377.95", WPF accende ben 512 pixel sul monitor da 130 DPI in risoluzione nativa di 1680x1050 e solo 236 su un monitor largo uguale che abbia però una risoluzione nativa di 800x600, ma entrambi i casi la misura è sempre 10 centimetri, e in tutti i casi la misura che voi avete specificato con WPF è sempre la stessa (377,95 DIU)!
Ora anticipo la prossima obiezione, che qualcuno di persona mi ha già fatto: d’accordo, ora è chiaro come tracciare misure fisse indipendenti dalla risoluzione. Ma a me non interessa. Io voglio continuare a beneficiare del fatto che sia l’utente a scegliere le dimensioni della mia applicazione semplicemente cambiando la risoluzione del monitor oppure, ma solo se è lui a deciderlo, modificando il DPI Scaling. Ebbene, non a caso il DIU misura 1/96 di pollice; infatti, per default quando installate Windows, la scala è impostata 96 DPI (vedi immagine sopra). Ciò significa che, se non viene cambiato il valore 96 di default, 1 DIU = 1 PIXEL. Quindi sviluppando in WPF avete entrambi i benefici: per default, funziona tutto come prima, ma se la vostra applicazione deve gestire dimensioni reali basta che chiediate all’utente di impostare DPI Settings al valore corretto per il suo monitor (semplicmente dividendo la larghezza del monitor per la risoluzione orizzontale); immaginate per esempio una calcolatrice touch screen: sarebbe molto scomodo che, portandola sul un monitor da 52 pollici full HD, occorresse uno spillo per premere i bottoni sul video per evitare che la punta del vostro dito pigi 3 bottoni insieme.
Infine, e sarà argomento di un prossimo post, seguendo questa strada con WPF diventa semplice scalare gli oggetti di interfaccia: avete mai visto un’applicazione che quando è portata a pieno schermo ingrandisce in proporzione tutti gli elementi contenuti nella finestra? Very complicato da implementare in un’applicazione tradizionale. Questo è il motivo per cui spesso si leggono warning del tipo l’applicazione richiede una risoluzione di 1024x768 o simili, che vogliono appunto dire che se hai risoluzione maggiore la vedi piccola, mentre se vai in 800x600 ti occupa più dello spazio visibile... non sarebbe meglio invece vederla per tutta la larghezza disponibile, eventualmente più definita al crescere della risoluzione?
Concludo con un parallelo, sempre relativo a WPF, fra Resolution Independence e Time Independence: in WPF quando portate un’animazione da un PC lento ad uno molto veloce, questa non accelera: come è giusto che sia, semplicmente diventa più fluida. Anche questo argomento sarà oggetto di un prossimo post.
Riferimenti
- Matthew MacDonald: Pro WPF in C# 2008 - Introducing WPF, by Apress, capitolo in parte riportato qui
- Charles Petzold: Applications = Code + Markup - Capitolo 1, by Microsoft Press
- Adam Nathan: Windows Presentation Foundation Unleashed - Enter WPF, by SAMS
In questo articolo vediamo come realizzare un'applicazione WCF partendo dall'esposizione dei principi di base, costruendone uno da zero in C# con VS2008, installandolo su IIS 7 e infine consumandolo con un client WPF.
Vi suggerisco di vedere prima lo screencast che segue -dura circa 10 minuti-, per avere un'idea di come si realizza un'applicazione di questo tipo, e poi provare a realizzare nuovamente la stessa seguendo passo passo il resto di questo post. Trovate i sorgenti del progetto a questo link.
Una volta predisposta una macchina per creare ed ospitare applicazioni WCF, il primo passo per capire come funziona WCF consiste nel studiarne l'ABC, non solo in senso figurato:
- A sta per Address, ovvero DOVE avviene la comunicazione; nella pratica, questo è l'URL utilizzato internamente per mappare richieste e risposte.
- B sta per Binding, cioè COME si comunica: tramite HTTP, TCP, NamedPipes, MSMQ, o altro protocollo che client e server entrambi capiscono.
- C è il Contratto: che COSA client e server si dicono; in particolare, esistono due tipi di contratto:
- Data Contract: le informazioni che client e server si scambiano, la cui struttura è indicata nello schema del servizio;
- Service Contract: i metodi invocati sul vostro servizio dal client, la cui firma (in gergo signature) è contenuta nel WSDL.
Partiamo lanciando Visual Studio 2008, ricordando di lanciarlo in modalità Amministratore se intendete utilizzare il server WEB della vostra macchina Windows Vista; ciò non è necessario se utilizzate il Personal Web Server.
Creiamo un nuovo progetto di tipo WCF (File-New Web Site...), scegliamo un nome e premiamo OK. Noterete che, come spesso succede, il progetto non è esattamente vuoto perché Visual Studio ci ha favorito inserendo qualche piccola porzione di codice, che normalmente lo sviluppatore deve sempre scrivere; in questo caso, però, poiché vogliamo capire esattamente i dettagli di WCF, lo "puliremo" quasi per intero.
Apriamo innanzi tutto il file App_Code\IService.cs e rimuoviamo tutto il codice tranne gli using iniziali che referenziano i namespace. In questo file si specifica l'interfaccia del servizio in termini di dati e metodi attraverso cui il servizio si espone all'esterno; notate la corrispondenza fra questi due termini e i due tipi di contratto che ho indicato sopra con lo stesso colore.
Partiamo con il Data Contract: definiamo due tipi che useremo per comunicare; potremmo usare tipi semplici come string e int, ma per fare un esempio semplice e al tempo stesso estensibile userò però due classi, ciascuna con un membro pubblico: chiamerò la prima Richiesta e la seconda Risposta:
Ora, affinché la classe sia serializzabile, l'autore deve definire il data contract che dicevo sopra. L'attributo [DataContract], applicato ad una classe o ad un tipo, specifica che la classe (o il tipo) definisce o implementa un data contract ed è serializzabile da un serializatore come System.Runtime.Serialization.DataContractSerializer; in modo simile, l'attributo [DataMember] deve essere applicato ad ogni membro pubblico che si vuole esporre della classe serializzata. Ecco quindi come devono essere modificate le due classi sopra per diventare parte del data contract:
Oltre al Data Contract io voglio ora implementare il Service Contract: in altre parole, voglio esporre un metodo. Tale funzione, che chiamerò RendiMaiuscolo, accetta un oggetto di classe Richiesta e restituisce un oggetto di classe Risposta creato all'interno della funzione stessa; si noti che così come il Data Contract richiede la coppia [DataContract] / [DataMember], in modo simile il Service Contract richiede l'attributo [ServiceContract] prima della definizione dell'interfaccia, e [OperationContract] per la definizione del metodo; in pratica, scriveremo così la sua signature:
Il prossimo passo consiste nell'implementare il contratto (in particolare il suo Service Contract) appena definito: apriamo il file App_Code\Service.cs, rimuoviamo tutto il codice e implementiamo l'interfaccia; si può anche chiedere a Visual Studio di generare il metodo automaticamente premendo il tasto destro sul nome dell'interfaccia IService da cui si eredita, come mostrato di seguito:
Le seguenti tre righe di codice creano un nuovo oggetto di tipo Risposta ed assegnano al suo membro StringaRisposta la stringa contenuta nell'oggetto richiesta che viene passato al metodo, trasformata in maiuscolo:
Per completezza di informazione aggiungo che l'ultimo snippet di codice avrebbe potuto contenere l'attributo [ServiceBehaviour] prima della definizione della classe Service che deriva dall'interfaccia IService, e l'attributo [OperationBehaviour] prima dell'implementazione del metodo RendiMaiuscolo; tuttavia, questi attributi sono opzionali.
Con l'ultima operazione abbiamo terminato la scrittura del servizio; provate a compilarlo, non devono esserci errori. È giunto quindi il momento di consumarlo.
A questo proposito aggiungiamo alla soluzione un nuovo progetto di tipo WPF (nel mio caso l'ho chiamato WpfApplication1) e un riferimento all'oggetto che implementa l'interfaccia IService appena sviluppata; si noti che premendo il bottone Discover, Visual Studio analizza la soluzione e ne mostra i servizi disponibili, quindi non dobbiamo far altro che selezionare l'oggetto che ci serve specificando un namespace per noi significativo (io l'ho chiamato ServizioDiTest):
Da questo momento in avanti è possibile utilizzare proprietà e metodi pubblici del servizio attraverso l'oggetto ServizioDiTest.ServiceClient.
Per testarlo, aggiungete un oggetto TextBox e un Button nel file Window1.XAML:
in modo da generare l'event handler dell'evento Click nel file Window1.xaml.cs, che riempiremo con queste 6 righe di codice che instanziano il servizio, usano il suo riferimento per creare l'oggetto richiesta e per creare un riferimento risposta alla classe Risposta di cui il servizio crea l'istanza nel metodo RendiMaiuscolo.
Impostate ore l'applicazione WPF come startup project e lanciatela: premendo il bottone, la stringa verrà convertita in maiuscolo:

La notizia, sempre gradita dal pubblico, che anticipo quando presento LINQ è che la sessione ha pochissime slide e molte demo.
In effetti l'argomento non è dei più intuitivi, specie per chi proviene da un tipo di sviluppo procedurale classico e non ha particolare esperienza di programmazione procedurale. Inoltre, al fine di cogliere appieno i vantaggi di questa tecnologia, occorre conoscere concetti quali i delegate, le lambda expression, il linguaggio SQL, i Dataset, un po' di XML e chiaramente il framework .NET con almeno un linguaggio fra C# e VB.NET.
Ciò premesso, i takeaways dell'intera presentazione su LINQ sono essenzialmente i seguenti:
- il linguaggio di interrogazione, SQL-like, si integra nel linguaggio di sviluppo (al momento C# 3.0 e VB.NET 9.0)
- tratta i dati come oggetti, e viceversa
- permette il passaggio dalla modalità imperativa a quella dichiarativa: è un po' la differenza che passa fra dare indicazioni di svolta a destra/sinistra/avanti/indietro ad un tassista invece che comunicargli una volta solamente l'indirizzo di destinazione
- funziona in modo molto simile per la gestione di dati, oggetti e stream XML
Le slide che trovate quindi a questo link sono quindi in minor numero rispetto al solito -fra l'altro, le prime tre riprendono i concetti (necessari) del Framework .NET-, ma come vi dicevo gran parte della presentazione prevede la scrittura di demo live per circa 90 minuti.
Seppure corredata di demo live che svolgo al momento, la sessione è pur sempre teorica; viene per questo completata da una esercitazione pratica, che i ragazzi possono svolgere sui PC dell'Università o personali. Trovate qui gli script di laboratorio, e in questo mio post precedente le istruzioni per predisporre la vostra macchina.
Ho presentato questo argomento recentemente a Salerno e Catania. Se siete in zona, e interessati, mi trovate a Venezia il 10 aprile, a Napoli il 15/4, a Milano Bicocca il 17/4, a Bologna il 27/5 e a Torino l'11 giugno; più in generale, trovate le date dei nostri eventi pubblicate sul sito degli studenti (http://www.microsoft.com/italy/studenti/).
Inizialmente si potrebbe approcciare questo argomento con scetticismo, dal momento che complica il panorama di tipi .NET conosciuti che tipicamente presentano campi semplici, proprietà, metodi ed eventi; ma si cambierà idea non appena capìti i problemi risolti attraverso le dependency property, che possono essere sfruttate per abilitare il data binding automatico, le animazioni, gli stili e molto altro. Diventa così possibile, per esempio, scrivere nel codice di markup (XAML) operazioni di layout (dipendenti per esempio dalla posizione del mouse) che altrimenti si dovrebbero gestire da codice procedurale (C# o VB.NET).
Una dependency property dipende da diversi provider per determinare il suo valore in ogni momento; l’obiettivo è di permettere funzionalità avanzate direttamente dall’interno del linguaggio di markup, senza bisogno di impostare le proprietà con codice procedurale.
Implementazione di una Dependency Property
Le dependency property sono normali proprietà di classi .NET che hanno una particolare struttura che le rende fruibili da WPF in modo speciale; nessun altro linguaggio .NET a parte XAML le riconosce come tali.
Per convenzione, tutti i campi DependencyProperty sono pubblici, statici e hanno il suffisso Property.
Poiché le dependency property sono campi statici, esse consumano una quantità di memoria di molto inferiore rispetto a che se fossero tipiche proprietà .NET di cui esiste in memoria una copia per istanza. Non a caso, 78 proprietà su 96 dei bottoni sono dependency property.
Una dependency property è implementata attraverso una chiamata al metodo statico DependencyProperty.Register che richiede un nome (es. IsMouseOver), un tipo (es. bool), il tipo della classe che le espone (es. Button) e, nella maggioranza dei casi, il nome della funzione di callback che viene chiamata quando tale proprietà cambia.
Change Notification
L’implementazione della callback nelle dependency property prende il nome di Change Notification; per rimanere nell’esempio precedente, la proprietà IsMouseOver permette di legare il suo valore (che dice quindi se il mouse si trova effettivamente sul controllo che la utilizza) ad un’altra proprietà del controllo stesso, come Background. Ciò significa che in questo caso non è necessario gestire il background del controllo andando a scrivere codice per l’event handler di MouseEnter e MouseLeave come vorrebbe il metodo classico, il quale fra l’altro “sporca” la business logic del file C# con codice di gestione del layout.
Grazie all’implementazione descritta nel punto precedente, è invece possibile legare il cambiamento di valore di IsMouseOver (da True a False o viceversa) al valore della proprietà Background del bottone.
Il video che segue mostra appunto come sfuttare le dependency property per impostare il colore di un bottone quando il mouse ci passa sopra. Normalmente potremmo implementare questo comportamento andando a definire e poi implementare, in codice procedurale C# o VB.NET, gli event handler per gli eventi di MouseEnter e MouseLeave. Grazie alle dependency property, invece, è possibile implementare questo comportamento solamente usando il codice di markup (XAML). Vediamo quindi come effettuare questa operazione, prima con il metodo classico e poi con le dependency property. Buona visione.
WPF fornisce supporto integrato per i comandi, permettendo di associare a ciascuno di essi una funzione di risposta alle principali azioni che su di essi si possono compiere; per comandi si intende quelle operazioni classiche di Windows quali Copy, Paste, AlignRight, Close, Open, Undo, ScrollDown, PreviousTrack ed un altro centinaio, che WPF raggruppa in cinque classi: ApplicationCommands, ComponentCommands, MediaCommands, NavigationCommands ed EditingCommands, di cui trovate ampia documentazione su MSDN e in generale sulla rete.
Le "principali azioni" relative ai comandi sono tre: 1) la loro esecuzione, 2) la verifica sul fatto che possano essere effettivamente eseguite e 3) la notifica dello stato di cambiamento della loro disponibilità; per fare un esempio, la funzione incolla prevede come esecuzione l'estrazione dell'informazione dalla clipboard e la sua scrittura nell'elemento di destinazione (es. una TextBox), prevede come verifica il fatto che esista un'informazione in clipboard e come notifica il fatto che la clipboard passi da vuota a piena o viceversa; in questo modo posso utilizzare le tre funzioni per abilitare o disabilitare un bottone che ne implementa il comportamento.
Una volta associato il comando ai nomi delle tre funzioni di risposta (per la precisione questa operazione si chiama CommandBinding), è possibile sfruttare un altro potente servizio offerto da WPF per legare il comando ad un controllo che può essere di tipo Button, CheckBox o MenuItem; da quel momento, premere il bottone richiamerà la funzione designata alla esecuzione, e la proprietà IsEnabled dello stesso sarà automaticamente legata al risultato della funzione di verifica. In più, se il comando prevede una combinazione di tastiera (come il CTRL-V per la funzione Incolla), digitando la stessa otteniamo gratis il biding dello shortcut alla funzione di esecuzione, esattamente come se avessimo premuto il bottone ad essa riferito.
Non vi ho convinto? In effetti, per chi proviene come me da esperienza di programmazione procedurale, risulta a volte difficile percepire il vantaggio di un sistema -come WPF- che fornisce già integrato il supporto per operazioni che siamo sempre stati finora abituati a gestire manualmente: che problema c'è? - mi sono chiesto la prima volta che ho studiato questo argomento - basta scrivere l'operazione nella funzione di risposta al click del bottone.
Per meglio rendermi conto della differenza ho provato ad implementare la funzione incolla in modo tradizionale e poi sono passato al command binding di WPF, e devo confessarvi che mi sono ricreduto: quasi per magia (il mio collega e amico Dario Airoldi , scherzando, mi ha chiamato Silvan quando ha visto la mia piccola demo :-)), continuavo a rimuovere decine di righe di codice che avevo scritto fino a scendere a zero istruzioni C# e due soli attributi del bottone in XAML, e il programma continuava a funzionare anche meglio di prima (per esempio, potevo evitare di monitorare lo stato della clipboard con un timer)!
In effetti, riflettendoci bisogna ammettere che è quasi imbarazzante che io spieghi a Windows che quando premo CTRL-V lui deve andare a prendere il contenuto della clipboard e scriverlo nel controllo con il focus: dovrei solo potergli dire incolla! e poi saprà ben lui come fare, non vi pare?
Se vi ho incuriosito a sufficienza, potete guardarvi lo screencast del mio test che ho descritto sopra, che ho registrato in modo amatoriale (dovrete alzare un po' il volume, ed è sicuramente migliorabile) per il mio archivio personale ma che credo possa aiutare nella comprensione di questo argomento.
Vi auguro buona visione. Alla prossima
Anche la seconda serie di seminari che sto portando in giro per l'Italia prevede, nella maggioranza dei casi, una mattinata dedicata all'approfondimento teorico di alcune architetture e tecnologie, ed esercitazioni pratiche il pomeriggio sugli argomenti prima presentati.
Per sfruttare al meglio il tempo a disposizione, è necessario preparare i PC in anticipo; si tenga presente che a seconda della configurazione di partenza del PC, della disponibilità del materiale da installare (su DVD o con download dal sito Microsoft), la configurazione può richiedere anche alcune ore; in questo post riassumo le istruzioni, che variano a seconda della tipologia di esercizi da svolgere. In particolare, occorre avere installati:
- Per le esercitazioni su ASP.NET, ADO.NET e Master Pages, scaricare il file HOL.ZIP e seguire istruzioni per la configurazione contenute in questo post o nel file 00-INSTALLAZIONE LABORATORIO.PDF contenuto in HOL.ZIP
- Le esercitazioni su LINQ richiedono come configurazione minima una versione qualunque di Microsoft Visual Studio 2008 (*) installata con i parametri di default, e la presenza sul PC di SQL Server 2005 (versione Express, installata da Visual Studio, oppure un’altra versione commerciale); servono inoltre i seguenti due file:
- Il database NorthWind, da aggiungere ai database di SQL Server, per gli esercizi di LinQ to Dataset e LinQ to SQL
- Il file Customers.XML, per gli esercizi di LinQ to XML
- Per le esercitazioni su Sviluppo Mobile, serve avere installati:
(*) Le seguenti opzioni sono disponibili per ottenere Microsoft Visual Studio 2008:
- Utilizzare l’account MSDN-AA (Academic Alliance) fornito dall’Università, che consente a tutti gli studenti afferenti del dipartimento che lo ha sottoscritto di accedere gratuitamente al software Microsoft, fra cui tutti i sistemi operativi, i prodotti server e i prodotti di sviluppo, incluso Visual Studio 2008 Professional;
- Scaricare la versione gratuita di valutazione di Visual Studio Professional 2008, completamente funzionante per 3 mesi.
Recentemente ho presentato un seminario all'Università Tor Vergata di Roma ad un pubblico di studenti che includeva in maggioranza persone del Corso di Ingegneria del Software.
Con il Prof. D'Ambrogio abbiamo quindi concordato di dare particolare risalto alle tematiche di gestione del ciclo di vita del software; come probabilmente sapete, Microsoft ha sviluppato negli anni una serie di metodologie, best practice, mentalità, modelli, discipline e altre esperienze che ha poi raccolto e pubblicato, in diverse fasi, sotto il nome di MFS (Microsoft Solution Framework).
La prima versione risale all'inizio degli anni '90, è stata resa pubblica nel 1993 ed è poi stata aggiornata nel corso degli anni: nel 1998 con la versione 2 e nel 2003 con la versione 3, fino ad arrivare all’ultima versione (la 4) rilasciata nel 2006 assieme alla famiglia Visual Studio Team System e al Team Foundation Server.
A partire dalla versione 4, MSF è utilizzabile sia senza uno strumento, sia in combinazione con Team Foundation Server, Team Explorer, Windows Sharepoint Services, Reporting Services, Microsoft Project e Microsoft Excel, che danno accesso alle funzionalità di pianificazione, gestione della documentazione e del codice sorgente, tracciamento di attività, bug, rischi e molto altro ancora.
Il mio intervento si è focalizzato prima sull'analisi delle cause principali di fallimento di progetti IT, ne ha cercato di identificare le soluzioni più efficaci, ha presentato il framework MSF utilizzato internamente dalla stessa Microsoft per la gestione dei suoi prodotti e infine ha coperto la parte di strumenti software client e server -Visual Studio Team System- che sfruttano i principi prima discussi integrandosi perfettamente con MSF 4.
Spero di farvi cosa gradita mettendovi a disposizione le slide della mia presentazione; se non avete usato un tool di supporto al ciclo di vita del software finora, vi invito a considerare seriamente la soluzione proposta da Microsoft: che dobbiate sviluppare un piccolo software per l'esame del corso universitario insieme ad un compagno, o che siate responsabili di progetti IT di gradi dimensioni, avere una metodologia agile, flessibile e potente ripagherà ampiamente il tempo investito e vi consentirà di arrivare al termine del progetto on budget, on time e on target ;-)!
Durante i seminari su ASP.NET che ho portato in giro per l'Italia nel primo semestre dell'anno accademico 2007-2008, come di consueto abbiamo raccolto feedback che ci aiutino a migliorarli e spunti per gli argomenti di successivi approfondimenti.
Uno dei più richiesti è lo sviluppo per dispositivi mobili, che ho provveduto ad inserire nel ciclo di seminari del secondo semestre.
La presentazione, di circa 90 minuti, parte dalla esposizione delle tre piattaforme embedded di Microsoft (Micro Framework, Windows CE e XP Embedded) per focalizzarsi poi sui sistemi operativi dedicati a Windows CE (da Handled PC a Windows Mobile 6) e in particolare sui loro allestimenti (come gli Smartphone); a questo proposito trovate maggiori approfondimenti su questo mio post precedente.
La presentazione passa poi ad analizzare le due modalità di programmazione (Managed e Nativa) e in particolare la prima delle due, grazie all'ultima versione del Compact Framework (la 3.5) che è disponibile in Visual Studio 2008; BTW: il Compact Framework 3.5 copre il 30% delle funzionalità del Framework .NET 3.5 nell'8% di spazio, ovvero per installarlo vi occorrono solamente 6.2 MB liberi sul dispositivo. Fra le altre cose supporta WCF, Link, Direct3D ed integra SQL Embedded.
Risalto particolare viene dato agli emulatori, ora giunti alla versione 3, che permettono di provare le vostre applicazioni su decine di diverse configurazioni senza doverli avere fisicamente disponibili; personalmente trovo che la "user experience" è enormemente migliorata con l'ultima versione del device emulator, permettendo di simulare operazioni quali la connessione al cradle, l'installazione una rete 3G ed è possibile perfino effettuare chiamate telefoniche e mandare SMS. Provare per credere.
Naturalmente, se avete un dispositivo basato su Windows CE (come un Pocket PC o uno Smartphone), e questo non è bloccato, potete anche fare il deployment delle vostre applicazioni, magari via Bluetooth, che a me personalmente ha dato una notevole soddisfazione. Maggiori informazioni sul collegamento ActiveSync via bluetooth sono disponibili a questo indirizzo.
Spero di fare cosa gradita mettendovi a disposizione la mia presentazione. Quanto ai laboratori, se volete esercitarvi con uno script che vi guidi passo passo alla realizzazione di un progetto completo, vi suggerisco questo mio post precedente.
Se poi qualcuno si trova nei paraggi ed è interessato, ne parlerò a La Sapienza (Dip. di Informatica e Sistemistica "Antonio Ruberti" di Via Ariosto n. 25 a Roma) il 4 marzo 2008, poi ancora a Salerno (Università di Fisciano) il 4 aprile, a Milano Bicocca il 17 aprile e più in generale trovate i nostri eventi aggiornati sul sito Microsoft 4U.
Un mio post precedente sull'uso dei delegate ha generato un lungo follow-up con sviluppatori interessati ad approfondire l'argomento; in particolare, numerose domande riguardavano l'utilizzo dei delegate in funzioni di callback, in chiamate asincrone, nello scorrimento di liste generiche e, naturalmente, nell'integrazione dei delegate in LinQ. Approfitto di questa nota anche per ricordare che è preferibile e più efficiente postare le vostre domande in fondo ai miei blog, invece di scrivermi per mail, così da condividere le nostre interazioni con il resto della community ;-).
L'utilizzo dei delegati negli scenari descritti sopra prevede l'approfondimento di un tipo particolare di delegate, ovvero gli Anonymous Delegate. A questo scopo ho preparato il seguente listato che mostra l'implementazione degli anonymous delegate in diverse situazioni; non cercate di leggerlo subito perché è commentato nel resto del post, ma magari stampate l'immagine linkata che è ad alta definizione per prendere appunti durante la lettura del resto di questo post:
Come dicevo, ho riassunto tutto il codice insieme per poter meglio confrontare i dettagli che ora vado a spiegare, relativi al pezzettino di volta in volta evidenziato.
Iniziamo ricapitolando il normale uso dei delegati NON anonimi; in pratica, definita una funzione (somma nel mio esempio), la richiamo attraverso un oggetto delegate -che ho chiamato CalcoloDelegatoEsplicito) di CalcoloDelegato che è una classe "tipo puntatore a funzione" (buona definizione di delegate) ad una generica funzione che riceve due interi (a e b) e ne restituisce un terzo; si noti che è stata necessaria una New per instanziare CalcoloDelegatoEsplicito, a sostegno del fatto che i delegate non sono semplici alias bensì delle classi del .NET framework:
Ora facciamo la stessa cosa utilizzando però un Anonymous Delegate, ovvero rimuovendo la funzione somma e spostandone l'implementazione inline. Si noti che in questo caso non è necessario usare la New per creare l'istanza del delegate; infatti, il compilatore C# è in grado di capire da solo che deve effettuare le seguenti operazioni:
- Inferire i valori di ritorno della funzione anonima (ovvero capire che restituisce un intero)
- Istanziare un nuovo oggetto delegate del tipo dedotto al punto precedente
- Wrappare il nuovo delegate intorno al metodo anonimo
- Assegnare quest'ultimo allo specifico delegate CalcoloDelegato
Le uniche istruzioni necessarie a ottenere il risultato sono dunque quelle di seguito evidenziate:
Ora facciamo un salto di astrazione: usiamo la funzione InvocaDelegateSpecifico che accetta come parametro uno SPECIFICO delegate (in questo caso si aspetta un delegate della classe CalcolaDelegato, che noi le passiamo dopo averlo creato inline come anonymous delegate):
Vediamo l'ultimo caso: funzioni che prendono un delegate astratto, come la InvocaDelegateAstratto(Delegate calcolodelegatoastratto); in questo caso dovete prima effettuare il cast ad uno specifico delegate:
Infine, il caso più interessante: un esempio utile e concreto in cui il costruttore della classe Thread (ma potrebbe essere il metodo Find delle collection) richiede il nome di una funzione senza parametri da lanciare in un thread separato; in questo caso noi gli passiamo un delegate anonimo costruendogli inline le istruzioni da eseguire, che lui riceve come delegate astratto:

Un'ultima cosa prima di concludere: nel paragrafo precedente menzionavo che le collection hanno un metodo Find che, in un'unica istruzione, consente di estrarre l'elemento desiderato semplicemente passando a questa funzione la condizione di ricerca (che fa anche uscire dal ciclo); immaginate per esempio di avere una classe Cliente (con un paio di metodi pubblici come nome e città) e una collezione di clienti (che chiamate Clienti) definita con l'istruzione List<Cilente> Clienti = new List<Cliente>(); Ora, per trovare il primo cliente della lista la cui città è Milano, possiamo scrivere la seguente singola istruzione:
- Cliente cliente = Clienti.Find(delegate (Cliente c) {return c.Città="Milano";});
Ebbene, la parte che ho sottolineato è proprio un delegate anonimo che prende in ingresso un parametro di classe Cliente che viene passato alla funzione Find che si aspetta un delegate astratto contenente l'istruzione di ricerca (quella fra parenti graffe).
Ma c'è di più: il C# 3.0 che è parte di Visual Studio 2008 consente di ridurre ulteriormente l'istruzione sopra sfruttando le cosiddette LAMBDA EXPRESSION: infatti potete ridurre il codice alla seguente istruzione, che significa esattamente la stessa cosa:
- Cliente cliente = Clienti.Find(c => c.Città="Milano");
Mi rendo conto che l'argomento è un po' ostico, e probabilmente se non venite da esperienza di programmazione funzionale vi troverete un po' perplessi a valutare l'utilità di comprimere il codice così tanto. Se vi può consolare, vi confermo che l'alternativa c'è, ovvero scirversi un bel ciclo ForEach che si spazzoli tutti gli elementi della collezione; a quel punto però perdereste il vantaggio di poter passare come parametro la funzione che contiene la condizione di ricerca, che dovrebbe essere sostituita per esempio da una stringa (di cui dovreste fare i parsing) oppure da una serie di parametri per valutare condizioni quali i record con le città che iniziano per una certa lettera, o quelli con il nome utente composto da due parole, o quelli con il nome utente uguale al nome della città... ovviamente questi sono esempi di pura teoria visto che ho creato per semplicità una tabella con due soli campi stringa, ma vi possono dare un'idea del vantaggio di utilizzare funzioni generiche sfruttando gli anonymous delegate.
Se vi interessa approfondire l'argomento, io ho trovato ispirazione in questo articolo.
Fatemi sapere se il post vi è piaciuto. Cordialità
Dopo i primi post introduttivi sulla piattaforma Windows Mobile, necessari per approcciare questo argomento, in molti mi hanno chiesto di mostrare come creare nella pratica un'applicazione da zero. Oggi realizzeremo quindi un programma per Smartphone completo e funzionante basato su Compact Framework 3.5, Microsoft SQL Server Compact 3.5 e le classi legate al Pocket Outlook preistallato sul dispositivo, utilizzando la versione Professional di Visual Studio 2008.
Inizieremo con la teoria, esaminando gli oggetti del Compact Framework 3.5 che consentono l'accesso a SQL Mobile; vi darò poi un breve esempio di come creare le classi per accedere ad un database mobile vero (che potete scaricare dai link sotto riportati), quindi vi guiderò a realizzare un esempio passo passo testandolo sull'emulatore incluso in Visual Studio 2008 o, se avete letto il mio post sul collegamento bluetooth, anche su un dispositivo fisico. Se avete un minimo di basi tecniche sullo sviluppo .NET, e avete letto il mio post di introduzione alla piattaforma mobile, in meno di un'oretta sarete in grado di creare da soli la prossima applicazione. E allora, che cosa stiamo aspettando? Mettiamoci all'opera!
Iniziamo dalla definizione di DataSet, valida in generale con ADO.NET: tale oggetto rappresenta un insieme di viste -chiamate DataTable- associate al nome del DataSet. Per esempio, un DataSet potrebbe chiamarsi ANAGRAFICA e contenere una vista relativa all'anagrafica clienti (chiamata CLIENTI), una dei fornitori (FORNITORI) e una per i dipendenti (DIPENDENTI). Nell'esempio che segue avremo un dataset OrdersDataSet contentente una singola vista chiamata Inventory.
Nota: in questa esposizione, i caratteri evdienziati in blu rappresentano i nomi scelti dallo sviluppatore assegnati agli oggetti, mentre la parte in rosso è quella aggiunta da Visual Studio. In grassetto sono invece indicate le keyword della class library e del linguaggio C#.
Quando si crea un DataSet (NomeDataset) contenente una DataTable (NomeVista) utilizzando il Visual Studio 2008, viene generato in particolare un file NomeDataset.XSD che rappresenta il dataset in formato XML –che il designer mostra in formato grafico- e in più il file NomeDataset.Designer.cs che contiene, fra altro, la definizione delle seguenti quattro classi:
- La classe NomeDataset, che rappresenta appunto il dataset
- Le seguenti classi figlie di NomeDataset:
- NomeVistaDataTable, che rappresenta la vista all’interno del dataset
- NomeVistaRow, che rappresenta un record di NomeVistaDataTable
- NomeVistaTableAdapter, che indica come la vista è riempita dalla sorgente dati. Quindi un TableAdapter contiene principalmente:
- La stringa di connessione
- I comandi per SELECT, INSERT, UPDATE, DELETE
Le due classi NomeVistaDataTable e NomeVistaRow sono fortemente tipizzate e rappresentano i dettagli della vista definita nel DataSet; possono quindi essere usate nel codice sfruttando le proprietà che si mappano 1:1 sui campi della vista corrispondente; in altre parole, per ogni campo della vista NomeVista esiste una corrispondente proprietà nell’oggetto NomeVistaRow.
Un’applicazione mobile che deve leggere i record di un datatable utilizza gli oggetti DataSet e TableAdapter spiegati sopra; in più, deve creare un oggetto BindingSource, che serve a eseguire le operazioni di spostamento, conteggio dei record, calcolo della posizione, recupero del record corrente etc. Tale oggetto contiene, fra gli altri, anche l’evento CurrentChanged che viene richiamato ogni volta che ci si sposta di record in record. La creazione dell’oggetto BindingSource e relativa configurazione con DataSet e TableAdapter può essere effettuata automaticamente dal Visual Studio se trascinate sulla form un campo (o un’intera tabella) prendendola dalla finestra “Data Sources”; by default, l’oggetto così creato si chiamerà NomeVistaBindingSource, di tipo BindingSource, che contiene anche l’evento NomeVistaBindingSource_CurrentChanged che viene richiamato ogni volta che un record viene mostrato sulla form.
Esempio
Prendiamo un database di tipo Microsoft SQL Server Compact 3.5 chiamato Orders.sdf, che contiene la tabella Inventory. Creiamo un data source (che chiamiamo OrdersDataSet) di tipo Microsoft SQL Server Compact 3.5, leghiamolo a Orders.sdf e includiamo Inventory nella configurazione del DataSource. Se eseguiamo questa operazione utilizzando il menu Data – Add New Data Source..., il VS 2008 crea automaticamente le seguenti classi nel file OrdersDataSet.Designer.cs:
- classe OrdersDataSet
- classe OrdersDataSet.InventoryDataTable
- classe OrdersDataSet.InventoryRow
- classe InventoryBindingSource
- classe InventoryTableAdapter
La proprietà Current di InventoryBindingSource mantiene un riferimento ad un oggetto DataRowView che corrisponde alla riga mostrata; in pratica, rappresenta un record di una tabella e come tale può essere utilizzato attraverso le sue proprietà per essere cancellato, modificato, letto etc.
Ma in particolare la sua proprietà Row è un oggetto di tipo OrdersDataSet.InventoryRow.
Ciò significa che posso dichiarare un oggetto di tipo OrdersDataSet.InventoryRow e poi assegnargli InventoryBindingSource.Current.Row; poiché però Current è di tipo Object, devo fare due cast:
- DataRowView rowView = (DataRowView) InventoryBindingSource.Current;
- OrdersDataSet.InventoryRow row = (OrdersDataSet.InventoryRow) rowView.Row;
A dimostrazione del fatto che le classi create dal designer sono fortemente tipizzate, si noti che il campo ImageFileName (di tipo stringa) della tabella Inventory è rappresentato da row.ImageFileName, e per esempio può essere utilizzato per creare e mostrare l’immagine in un oggetto di tipo PictureBox chiamato MyPictureBox che posizioniamo sulla form:
- MyPictureBox.Image = new Bitmap(row.ImageFileName)
Step by Step
Lanciamo il Visual Studio 2008 Porfessional (le versioni Express non includono la parte di sviluppo mobile) e creiamo un nuovo progetto di tipo Smart Device chiamato OrderManager, basato sul Compact Framework 3.5, il C#, piattaforma Windows Mobile 5 per Smartphone e template per Device Application; in altre parole, stiamo creando un’applicazione finestra da far girare su uno Smartphone che monta il Compact Framework 3.5:
Scarichiamo il file di database Orders.sdf di tipo SQL Server Compact 3.5, che mettiamo in una cartella temporanea.
Dal menu Data, aggiungiamo un nuovo data source e leghiamolo al database scaricato al punto precedente creando una nuova connessione: 

Rispondete sì alla domanda che chiede di includerlo nel progetto:
Scegliete di includere la tabella Inventory -che è anche l'unica- e chiamate OrdersDataSet il DataSet così creato:
Ora prendiamo la form, dove è rappresentato in anteprima il device su cui verrà installata la vostra applicazione, e creiamo i menu Avanti e Uscita; non vi indico i passi dettagliati perché sono veramente banali per chi ha una minima esperienza di utilizzo del Visual Studio; per tutti i dettagli potete comunque consultare questo articolo:
Togliamoci subito il pensiero e implementiamo la risposta al menu di uscita; chiamatelo per esempio menuUscita poi fate doppio click su di esso e scrive questa singola istruzione:
private void menuUscita_Click(object sender, EventArgs e)
{
Application.Exit();
}
Ora dal menu Data scegliete Show Data Sources e poi selezionate Details dalla lista a discesa:
Tale scelta farà in modo che trascinando la tabella Inventory sulla form, verranno creati tante TextBox quanti sono i (quattro) campi della tabella; si noti che oltre alle TextBox, nella parte inferiore della form vengono creati (e automaticamente configurati) anche gli oggetti che servono a estrarre i dati, ovvero il DataSet (ordersDataSet), il BindingSource (inventoryBindingSource) e il TableAdapter (inventoryTableAdapter), come avevo anticipato nella sezione Esempio di questo post:

Ora rispondiamo alla pressione del tasto Avanti: fate doppio click sul menu e scrivete questa istruzione che incrementa il puntatore di uno, sfruttando anche l'operatore modulo (%) per consentire di ritornare al primo record se si preme Avanti quando ci si trova sull'ultimo record:
private void menuAvanti_Click(object sender, EventArgs e)
{
inventoryBindingSource.Position = (inventoryBindingSource.Position + 1)
% inventoryBindingSource.Count;
}
Vogliamo prenderci un po' di soddisfazione e provare l'applicazione? Premete F5 e selezionate l'emulatore per Windows Mobile 5; potrebbe volerci anche qualche minuto se la vostra immagine è pulita perché nel caso il Visual Studio deve installare prima il Compact Framework 3.5:
Se tutto va come deve, ecco comparire la vostra applicazione; verificate il funzionamento premendo il tasto Avanti e, alla fine, il tasto di uscita:
Che cosa possiamo aggiungere adesso? Beh, io direi che sarebbe meglio vedere le immagini che rappresentano i prodotti, piuttosto che leggerne solamente il nome del file, voi che ne dite? Allora, avanti...
Chiudete l'applicazione utilizzando il menu di uscita, ma lasciate attivo l'emulatore: risparmieremo così il tempo necessario a installare nuovamente il compact framework.
La prossima operazione consiste nel copiare nel dispositivo le immagini da mostrare; esse infatti non risiedono nel database; per accedere al "disco" del dispositivo si può procedere in vari modi, io vi suggerisco di stabilire una connessione via ActiveSynch verificando che le impostazioni del Windows Mobile Device Center prevedano l'ascolto sulla porta DMA (che è quella attraverso cui comunica l'emulatore):
A questo punto, in Visual Studio lanciate il Device Emulator Manager:

Localizzate l'immagine dell'emulatore che avete ancora in esecuzione in background e dal menu contestuale scegliete Cradle; tale operazione simula il collegamento fisico del dispositivo al PC e fa partire l'ActiveSync:
Dall'interno del Mobile Device Center scegliete "Browse the content of your device":
Ora con una semplice operazione di Drag&Drop copiate la cartella images dentro la root del dispositivo.
Bene: le immagini JPG ci sono. Ora dobbiamo solamente mostrarle ;-).
Riprendiamo la form, cancelliamo tutte le label tranne Price ed eliminiamo pure la TextBox che mostra il nome di file; infine trasciniamo nella form dalla barra degli strumenti un oggetto di tipo PictureBox (che chiamiamo myPicture) e impostiamone la proprietà SizeMode a StretchImage:
Vi ricordate quando all'inizio dicevo che l'oggetto BindingSource ha un metodo CurrentChanged che viene richiamato ogni volta che ci si sposta di record in record? E' arrivato il momento di usarlo: fate doppio click su InventoryBindingSource nella parte bassa della finestra Form1.cs ed inserite queste quattro istruzioni:
DataRowView rowView = (DataRowView)inventoryBindingSource.Current;
OrdersDataSet.InventoryRow row =
(OrdersDataSet.InventoryRow)rowView.Row;
Bitmap myBitmap = new Bitmap(row.ImageFilename);
myPicture.Image = myBitmap;
Come avevo anticipato sopra nella sezione Esempio, la proprietà Current di InventoryBindingSource mantiene un riferimento ad un oggetto DataRowView che corrisponde alla riga mostrata. Tale oggetto può essere utilizzato attraverso le sue proprietà per essere cancellato, modificato, letto etc. Ma in particolare la sua proprietà Row è un oggetto di tipo OrdersDataSet.InventoryRow. Ciò significa che posso dichiarare un oggetto di tipo OrdersDataSet.InventoryRow e poi assegnargli InventoryBindingSource.Current.Row; poiché però Current è di tipo Object, ho dobuto effettuare due cast.
Che altro possiamo fare per complicarci la vita e rendere questa applicazione ancora più interessante? Che ne dite, potremmo aggiungere una funzione che invia la bitmap per mail utilizzando Pocket Outlook dello Smartphone... Avanti allora.
Inannzi tutto, aggiungiamo i riferimenti agli assembly che gestiscono il Contact Picker, che è l'oggetto del Compact Framework che fornisce un facile accesso alla lista dei contatti; prendete il menu contestuale della cartella References, selezionate Microsoft.WindowsMobile.Forms e Microsoft.WindowsMobile.PocketOutlook e premete OK:
A proposito: se state facendo il deployment sull'emulatore, allora non vi sono contatti definiti, createne quindi un paio di prova. Spero non ci sia bisogno di istruzioni per questo... ;-)
Adesso aggiungete la dichiarazione Using all'inizio del file Form1.cs:
using Microsoft.WindowsMobile.Forms;
using Microsoft.WindowsMobile.PocketOutlook;
Ora aggiungiamo una voce "Invia" al Menu di destra, facciamo doppio click su di essa e inseriamo le istruzioni per recuperare le informazioni da inserire nel messaggio:
- prima creiamo un'istanza dell'oggetto ChooseContactDialog che chiamiamo contactPicker:
ChooseContactDialog contactPicker = new ChooseContactDialog(); - poi facciamo comparire la finestra di richiesta di selezione contatto e verifichiamo se ne è stato selezionato uno:
if (contactPicker.ShowDialog() == DialogResult.OK) { } - adesso, all'interno delle parentesi graffe al punto precedente, scriviamo le istruzioni per creare il messaggio e spedirlo con allegata la bitmap; a questo scopo dichiariamo una variabile chiamata rowView di tipo DataRowView e le assegnamo il valore della proprietà Current di inventoryBindingSource; notate che i passi sono molto simili a quelli utilizzati in precedenza per creare la bitmap:
DataRowView rowView = (DataRowView)inventoryBindingSource.Current; - Infine creiamo la variabile selectedProduct di tipo OrdersDataSet.InventoryRow e assegnamole il valore di rowView:
OrdersDataSet.InventoryRow row = (OrdersDataSet.InventoryRow)rowView.Row;
Adesso che abbiamo recuperato le informazioni da spedire, creiamo il messaggio di posta; a questo scopo dichiariamo un oggetto message di tipo EmailMessage e gli associamo i classici campi oggetto, corpo, destinatario e allegato:
EmailMessage message = new EmailMessage();
message.Subject = "The picture you requested";
message.BodyText = "Attached is the picture we discussed";
Recipient client =
new Recipient(contactPicker.SelectedContact.Email1Address);
message.To.Add(client);
Attachment attachedImage = new Attachment(row.ImageFilename);
message.Attachments.Add(attachedImage);
Da ultimo, spediamo il messaggio con l'istruzione Send; questo metodo richiede il nome dell'account di email da cui spedire, quindi se state usando l'emulatore via ActiveSync scrivete ActiveSync come nell'istruzione che segue:
message.Send("ActiveSync");
Abbiamo terminato: verificate di avere almeno un contatto con indirizzo di e-mail valido ed eseguite l'applicazione. Per testarla uscite dall'applicazione, lanciate Pocket Outlook e verificate che il messaggio si trovi in posta in uscita:
That's all folks. Qui trovate i sorgenti completi.
Mi scuso per il post un po' lungo, ma spero vi siate divertiti e lo abbiate trovato abbastanza chiaro. Lasciate pure i vostri commenti qui sotto, risponderò a tutti. Grazie dell'attenzione, vi auguro buon lavoro. Alla prossima.
Per stabilire una connessione Activesync fra un dispositivo mobile su cui è montato un sistema operativo Microsoft -come Pocket PC, Smartphone o Windows Mobile-, tipicamente si utilizza un normale cavetto USB; rispetto ad altri tipi di collegamento, infatti, questa scelta risulta più affidabile, più veloce e più pratica.
Tuttavia, è previsto poter anche effettuare il collegamento sfruttando il Bluetooth, a patto ovviamente che sia il dispositivo mobile che il PC siano dotati di questa interfaccia.
Nonostante i passi da seguire non siano in teoria particolarmente complessi, vi confesso che ho dovuto faticare non poco per poter raggiungere il risultato; ho pensato fosse utile quindi riassumere la procedura da seguire.
Nota: questa esposizione si basa sui componenti hardware e software elencati di seguito; potrebbe risultare lievemente differente utilizzandone altri o diverse versioni, per questo motivo ho cercato di spiegare nel dettaglio che cosa produce ogni singolo passaggio:
- Computer: Notebook Portége M400 con sistema operativo Windows Vista Ultimate
- Dispositivo mobile: I-Mate Smartphone SP5 con sistema operativo Windows Mobile 5
Iniziamo con la configurazione del sistema operativo sul notebook; Windows Vista Ultimate arriva già con pre-installato il Windows Mobile Device Center (Centro Gestione Dispositivi Windows Mobile per chi ha la versione italiana). Tuttavia, suggerisco in ogni caso di aggiornarlo scaricando dal nostro sito la versione 6.1; è disponibile in diverse lingue fra cui l’italiano, e c’è anche a 64 bit.
Lato Smartphone, attiviamo il Bluetooth:
- Communication Manager - Bluetooth - Attivato (o Raggiungibile)
Lato PC, dopo avere aggiornato o installato il Gestione Dispositivi Windows Mobile e verificato di avere l'ultima versione dello Stack Bluetooth (che per il PC in oggetto si chiama "v51012T_20070531.EXE" e si trova sul sito di supporto tecnico del produttore), occorre per prima cosa verificare che sto stack Bluetooth stia eseguendo il servizio di emulazione delle porte seriali; nel mio caso si procede facendo click con il tasto destro sull'icona Bluetooth della system tray area e impostando la casella apposita nel menu opzioni, oltre alla richiesta di autenticazione e della crittografia disponibile nel tab "Sicurezza":
A questo punto aggiungete una porta COM virtuale bluetooth che resti in ascolto sulle connessioni in ingresso; nel mio caso ho trovato libera la COM6:
Ora bisogna impostare il sistema operativo perché attivi autoamticamente il Windows Mobile Center quando viene stabilita la connessione: aprite dunque l'applet dal pannello di controllo e, nelle impostazioni di connessione, settate questi parametri; ovviamente, fondamentale è il numero di porta che se avete scelto diversa da COM6 dovete cambiare di conseguenza:
Torniamo sullo smartphone: lanciate l'ActiveSync dal menu Start, quindi dal Menu sulla destra scegliete l'opzione 7 (Connetti tramite Bluetooth):
Ora rispondete Sì alla domanda che vi chiede si intendete ricercare un nuovo dispositivo Bluetooth che supporti ActiveSync e impostate il pairing con il PC; come proposto dall'opzione di default, accettate la creazione di una porta in ingresso sullo Smartphone di tipo ActiveSync. ATTENZIONE: se la porta in ingresso che vi propone NON è ActiveSync bensì una generica porta seriale, non va bene; verificate che il Centro Connessione Dispositivi Mobile nel pannello di controllo sia in ascolto sulla porta COM che avete creato all'inzio.
Se tutto sta procedendo come da indicazioni, tornate al menu start, rilanciate l'ActiveSync e nuovamente dal menu sulla destra scegliete l'opzione 7 (Connetti tramite Bluetooth): automaticamente partirà la sincronizzazione sullo smartphone e quella sul PC:
That's all folks! Spero queste indicazioni vi siano state utili, sarò contento se lasciate un post per comunicare l'esito delle vostre prove.
Buon divertimento, buon lavoro e alla prossima.
Come annunciato in un precedente post, fra ottobre e dicembre 2007 sto portando in giro per l'Italia una serie di seminari di introduzione alle tecnologie Microsoft, in particolare focalizzati sullo sviluppo di applicazioni Internet con ASP.NET e AJAX, partendo dall'architettura del .NET Framework.
Fanno da contorno la realizzazione di scenari sull'integrazione di politiche di sicurezza (integrata con Active Directory o esterna con registrazione degli utenti su un server SQL), una panoramica sugli ambienti di sviluppo -anche gratuiti come Visual Web Developer-, tecniche di ottimizzazione come Pagine Master / Temi / Skin / Localizzazione della lingua, le novità delle tecnologie di accesso ai dati con ADO.NET. Maggiori informazioni sui contenuti sono disponibili in questo mio post precedente.
Al termine della presentazione e durante la giornata che passo con loro, molti studenti mi chiedono le slide che ho presentato; normalmente le lascio a disposizione del professore che le mette sulla intranet dell'Università e le copio dal mio portatile sulla chiavetta USB a chi me le chiede al momento.
Ieri sono stato a Napoli alla Federico II e per qualche disguido non sono riuscito a incontrare il professore, quindi ho promesso agli studenti che le avrei postate entro oggi sul mio blog. Le trovate dunque qui. Ai due link più sopra trovate invece un riassunto dei contenuti del seminario, tutte le date previste per i seminari che rimangono e le esercitazioni di laboratorio; purtroppo ieri si sono svolte in un contesto difficile per problemi organizzativi interni, mi scuso ancora con gli studenti e rimango a loro disposizione per ogni chiarimento tecnico che non è stato possibile vedere ieri.
Alla prossima. Mauro
Come avevo anticipato in un mio precedente post, sto portando avanti in questo periodo una serie di seminari su tecnologie Microsoft nelle principali città italiane.
Il tour prevede incontri in una ventina di Università entro Natale. Il seminario dura una giornata intera ed è gratuito; come ogni lezione in università, dunque, è dedicato agli studenti ma in ogni caso è aperto a chiunque sia interessato.
Vi elenco di seguito l'agenda delle giornate, l'abstract dei contenuti -entrambi questi punti possono variare leggermente da sede a sede in relazione a richieste specifiche- e le date finora programmate.
In base ai feedback che riceviamo e alla partecipazione degli studenti, valuteremo al termine se riproporre questo tour nel secondo semestre dell'Anno Accademico 2007-2008.
AGENDA
L’incontro, della durata di una giornata, viene suddiviso nelle seguenti parti:
- 4 ore durante la mattina in cui vengono esposti gli argomenti sotto indicati
- 4 ore durante il pomeriggio da tenersi in laboratorio per lo svolgimento di esercizi per realizzare esempi pratici e funzionanti relativi alle nozioni esposte durante la mattina; maggiori informazioni per la configurazione del laboratorio sono disponibili a questo indirizzo
- Install Party: un paio di happy hours durante cui gli studenti potranno ritirare o installare direttamente sul proprio pc software Microsoft e ottenere informazioni tecniche in un'atmosfera informale e piacevole
Verrà rilasciato un attestato di partecipazione e a tutti gli studenti partecipanti sarà distribuita una copia di Windows Vista, per uso personale.
Lo speaker –possibilmente personale di Microsoft- sarà a disposizione per tutta la durata dell’evento.
ABSTRACT
I contenuti trattati sono stati preparati per adattarsi a qualunque percorso del piano di studi, vengono infatti trattati argomenti di livello architetturale, corredati da esempi pratici e demo live, che sulla base dell’esperienza degli eventi organizzati negli anni passati abbiamo visto essere interessanti sia per per persone che si affacciano alle tecnologie Microsoft emergenti che per sviluppatori più esperti.
CONTENUTI TENCICI
- Il Framework .NET
o Architettura
o Standard ECMA
o Implementazioni CLI per Linux e Mac: indipendenza da piattaforma e linguaggio
- ASP.NET
o Evoluzione delle tecnologie di sviluppo per il WEB
o Il modello si sviluppo WEB server side
o Ciclo di vita della pagina ASPX (*)
- Internet Information Server (IIS)
o Architettura dei server WEB di Microsoft
- Introduzione a Visual Studio .NET 2005
o IDE e Controlli lato server (*)
o Debugging e Tracing (*)
- SICUREZZA: un modello estensibile
o Membership: come sfruttare la sicurezza integrata in Active Directory nella intranet (*)
o Scenari di autenticazione sulla extranet (*)
- SORGENTI DATI E CONTROLLI DATA-BOUND
o Evoluzione delle architetture di accesso ai dati
o Lo stato dell’arte: ADO.NET
o I DATASET, un caso particolare: accesso ai dati in modalità disconnessa(*)
- PERSONALIZZAZIONE DELLE APPLICAZIONI
o Localizzazione: l’applicazione parla la lingua del browser (*)
o Pagine Master, Temi e Skin (*)
- AJAX
o Concetti e Fondamenti
o Da dove partire: installazione lato client e lato server
o I componenti base: AJAX Extensions, Contro Toolkit, Library e Futures CTP
o XmlHttpRequest, ScriptManager e UpdatePanel (*)
(*) argomento corredato da demo live
DATE PROGRAMMATE
9 ottobre: Trieste
11 ottobre: Camerino
16 ottobre: Crema
18 ottobre: Padova
23 ottobre: Cosenza
24 ottobre: Salerno
26 ottobre: Torino (Politecnico)
6 novembre: Torino (Università)
9 novembre: Venezia
14 novembre: Napoli
20 novembre: Catania
27 novembre: Genova (Università)
29 novembre: Genova (Politecnico)
11 dicembre: Bologna (sede di Rimini)
12 dicembre: Bologna (sede di Bologna, facoltà di Fisica)
18 dicembre: Roma (Tor Vergata)
16 gennaio: Bari
L'immagine qui sopra introduce l'argomento che mi accingo a trattare oggi, che ha destato particolare interesse durante la presentazione del collega e amico Pietro Brambati su LinQ che lui ha dedicato agli Student Partner ospitati nei nostri uffici di Segrate questa settimana. L'accostamento è forse un po' forzato, tuttavia il significato è che così come il Parlamento italiano è delegato ogni cinque anni dai cittadini a prendere delle decisioni, gli oggetti Delegate sono demandati a rappresentare funzioni. L'aspetto peculiare è che l'associazione fra delegate e funzioni non è disponibile a tempo di compilazione. Ciò rende estremamente potente e utile l'uso dei delegate in casi in cui, come negli esempi che seguono, si voglia loggare l'avanzamento di un programma senza sapere, a compile time, quali informazioni devono essere passate; un'altra applicazione sono i sistemi event-driven quando si vuole che una porzione di codice venga eseguita quando scatta un evento come un mouse click.
Chi ha già usato i puntatori a funzione in C++ starà sicuramente facendo un parallelo con questi, il che è abbastanza corretto; si tenga presente però che essendo i Delegate degli oggetti esposti dalla libreria di classi del framework .NET, per precisione si dovrebbe dire che essi incapsulano un riferimento ad (uno o più) metodi pubblici di una classe e vengono normalmente passati a codice che li richiama senza sapere, se non a run-time, quale metodo sarà effettivamente invocato.
Partiamo dal caso classico in cui si richiama, senza delegate, un metodo pubblico di una classe. A tal proposito potete creare un nuovo progetto di tipo console con il Visual Studio (nel mio caso l'ho chiamato Delegati) e aggiungere, dentro il namespace, la seguente classe:
class FunzioniUtili
{
static public void Tracking(string localString) {Console.WriteLine(localString);}
}
Come si evince chiaramente, essa altro non fa che pubblicare un metodo Tracking che scrive sulla console la stringa che gli viene passata; questo metodo non restituisce alcun valore. Ho dichiarato il metodo come statico per evitare di dover istanziare un oggetto della classe prima di richiamarlo.
Creiamo ora un'altra classe nello stesso namespace, che useremo per testare il funzionamento delle diverse chiamate al metodo Tracking; il suo metodo TestMethod1() richiama Tracking in modo diretto:
class TestClass
{
static public void TestMethod1()
{FunzioniUtili.Tracking("chiamata diretta");}
}
Ci siamo: richiamiamo TestMethod1 dal main della nostra applicazione con l'istruzione TestClass.TestMethod1(); -che anche in questo caso non richiede l'istanziazione della classe in quanto si tratta di metodo statico- e avremo la stringa "chiamata diretta" stampata sulla console. Se non lanciate l'applicazione da riga di comando, ricordatevi di mettere l'istruzione Console.ReadLine(); prima della chiusura del main, altrimenti non farete in tempo a vedere il risultato ;-).
Adesso andiamo invece a richiamare Tracking utilizzando un oggetto delegate che