di Marco BellinasoIn questo periodo sono occupato quasi settimanalmente con lo Starting Innovation Tour, un ciclo di conferenze gratuite organizzate da Microsoft nelle principali città italiane per mostrare a sviluppatori e partner le principali novità di Vista e Office 2007. Dopo Catania, Napoli, Bologna, Bari e Roma, questa settimana tocca a Padova, poi Milano, Firenze e Torino. A mio parere la conferenza è davvero un'ottima occasione per chi non ha ancora visto con i propri occhi (o toccato con mano, con preferite) le nuove major release dei due prodotti principali di MS. Io mi occuperò delle sessioni su Office, ovvero:
- Sviluppo con Office 2007 Client Side: come sfruttare il nuovo formato XML dei documenti per modificare o creare nuovi documenti senza avere Office installato - da applicazioni desktop o web - nonchè una panoramica sulla creazione di add-in, Action Pane e ribbon custom.
- Windows SharePoint Services 3.0: nuove funzionalità per le liste e document library (cestino, supporto per versioning esteso, supporto RSS,...), nuovi template (blog e wiki tanto per essere moderni, ma altro ancora), utilizzo masterpage a-là ASP.NET 2.0, webpart, utilizzo workflow built-in o utilizzo del nuovo SharePoint Designer per la definizione dei propri flussi.
- Office SharePoint Portal 2007: Excel Services (il motore di calcolo di Excel direttamente sul server + rendering via browser + esposizione del motore tramite web service!), Forms Services (praticamente le form InfoPath via browser!) e Business Data Catalog (indicizzazione e visualizzzione di record presi da un qualunque database o fonte di accesso ai dati esterna)
Insomma, mi sembra ci sia un bel po' di roba da vedere Per non parlare delle bellissime e impressionanti demo grafiche fatte con WPF per Vista! Dai, ci vediamo ad una delle prossime tappe allora...
di Enrico SabbadinHo ripreso una macro che avevo scritto qualche anno fa: Essa impostava l'ordine di build dei progetti nella solution in base alle referenze tra i vari progetti.
VS.NET fa in automatico una cosa del genere quanod le referenze sono di tipo progetto, ma questo è un problema quando si devono gestire delle soluzioni che hanno un grado variabilità notevole in termini di progetti che la compongono.
Questo addin fa lo stesso mestiere per le referenze di tipo assembly... La routine è stata aggiornata alla versione 2005 per gestire i progetti di tipo ASP.NET / WEB Service che rappresntano un tipo specifico di progetto.
Option Strict On Imports System Imports System.Windows.Forms Imports EnvDTE Imports EnvDTE80 Imports System.Diagnostics
Public Module CalcDepends
Public Function GetBuildOutPutWindow() As OutputWindowPane Dim win As Window = DTE.Windows.Item( _ EnvDTE.Constants.vsWindowKindOutput) Return CType(win.Object, OutputWindow).OutputWindowPanes.Item("Build") End Function
Public Const c_prjtypeVBNET As String = "VBPROJ" Public Const c_prjtypeCS As String = "CSPROJ"
Public Enum projectType VBNET CSHARP UNKWOWN End Enum Public Function getProjectType(ByVal p_prj As Project) As projectType Dim l_prjtype As String = p_prj.FullName.Substring(p_prj.FullName.Length - 6).ToUpper If l_prjtype = c_prjtypeCS Then Return projectType.CSHARP ElseIf l_prjtype = c_prjtypeVBNET Then Return projectType.VBNET Else Return projectType.UNKWOWN End If
End Function
Public Sub CalcBuildDepends() Try GetBuildOutPutWindow.OutputString("++++++++++++++ ENTERING CalcBuildDepends ++++++++++++++" & vbCrLf) Dim l_bd As BuildDependency For Each l_bd In _ DTE.Solution.SolutionBuild.BuildDependencies l_bd.RemoveAllProjects() Next
For Each l_prac As EnvDTE.Project In _ DTE.Solution.Projects If TypeOf l_prac.Object Is VSLangProj.VSProject Then If getProjectType(l_prac) = projectType.CSHARP Or getProjectType(l_prac) = projectType.VBNET Then Dim l_ActVSProject As VSLangProj.VSProject = CType(l_prac.Object, VSLangProj.VSProject) ' I get the Assembly Name of the Current Project For Each ref As VSLangProj.Reference In l_ActVSProject.References For Each l_pr As EnvDTE.Project In DTE.Solution.Projects ' looking for projects in the solution that are in the current project references list If TypeOf l_pr.Object Is VSLangProj.VSProject Then If getProjectType(l_pr) = projectType.CSHARP Or getProjectType(l_pr) = projectType.VBNET Then Dim l_VSProject As VSLangProj.VSProject = CType(l_pr.Object, VSLangProj.VSProject) 'GetBuildOutPutWindow.OutputString("Checking if " _ ' & l_ActVSProject.Project.Name _ ' & " references " _ ' & l_pr.Properties.Item("AssemblyName").Value.ToString & vbCrLf)
If (l_pr.Properties.Item("AssemblyName").Value.ToString = ref.Name) Then Try DTE.Solution.SolutionBuild.BuildDependencies.Item( _ l_ActVSProject.Project).AddProject(l_pr.UniqueName) GetBuildOutPutWindow.OutputString("**** Adding Reference " & l_pr.Name & " to " & l_prac.Name + " *****" & vbCrLf) System.Windows.Forms.Application.DoEvents() Catch ex As System.Exception MessageBox.Show("Error adding dependency " + l_pr.UniqueName + _ " to " + l_ActVSProject.Project.Name + " Error is:" + _ ex.Message) End Try End If End If End If Next Next End If ElseIf TypeOf l_prac.Object Is VsWebSite.VSWebSite Then Dim l_ActVSProjectWS As VsWebSite.VSWebSite = CType(l_prac.Object, VsWebSite.VSWebSite) For Each ref As VsWebSite.AssemblyReference In l_ActVSProjectWS.References For Each l_pr As EnvDTE.Project In DTE.Solution.Projects If TypeOf l_pr.Object Is VSLangProj.VSProject Then If getProjectType(l_pr) = projectType.CSHARP Or getProjectType(l_pr) = projectType.VBNET Then Dim l_VSProject As VSLangProj.VSProject = CType(l_pr.Object, VSLangProj.VSProject) 'GetBuildOutPutWindow.OutputString("Checking if " _ ' & l_ActVSProject.Project.Name _ ' & " references " _ ' & l_pr.Properties.Item("AssemblyName").Value.ToString & vbCrLf)
If (l_pr.Properties.Item("AssemblyName").Value.ToString = ref.Name) Then Try DTE.Solution.SolutionBuild.BuildDependencies.Item( _ l_ActVSProjectWS.Project).AddProject(l_pr.UniqueName) GetBuildOutPutWindow.OutputString("**** Adding Reference " & l_pr.Name & " to " & l_prac.Name + " *****" & vbCrLf) System.Windows.Forms.Application.DoEvents() Catch ex As System.Exception MessageBox.Show("Error adding dependency " + l_pr.UniqueName + _ " to " + l_ActVSProjectWS.Project.Name + " Error is:" + _ ex.Message) End Try End If End If End If Next Next End If Next GetBuildOutPutWindow.OutputString("++++++++++++++ EXITING CalcBuildDepends ++++++++++++++" & vbCrLf) 'MessageBox.Show("Recalculation Done") Catch ex As System.Exception MessageBox.Show("Error in seek:" + ex.Message) End Try End Sub
End Module
di Giuseppe Dimauro

Ciao a tutti, vi riporto di seguito il calendario ufficiale dei prossimi webcast architetturali tenuti da Maurizio, Pierre, me ed altri. Il primo appuntamento e' domani. Illustrero' le novita' della rinnovata versione dell'Enterprise Library di Patterns & Practices per poi proseguire fino a giugno con una nutrita serie di argomenti e approfondimenti su tecnologie reali.
Calendario dei prossimi Architect Webcast
§Febbraio
•7/2: Pattern architetturali per la realizzazione di applicazioni e servizi - Parte I
•14/2: Pattern architetturali per la realizzazione di applicazioni e servizi - Parte II
•21/2: Introduzione alla metodologia agile MSF 4.0 con Visual Studio 2005 Team System
•28/2: Progettare il Web Testing nel mondo Enterprise con Visual Studio 2005 Team Test
§Marzo
•07/3: BizTalk Server 2006: uno strumento per tutta l'azienda
•14/3: BizTalk Server 2006: mille e uno usi di uno strumento versatile
•21/3: BizTalk Server 2006 e lo sviluppo di applicazioni orientate ai servizi
•28/3: WinFX: Windows Workflow Foundation - Parte I
§Aprile
•04/4: WinFX: Windows Workflow Foundation - Parte II
•11/4: Realizzare servizi distribuiti con Windows Communication Foundation - Parte I
•19/4: Realizzare servizi distribuiti con Windows Communication Foundation - Parte II
•27/4: Architettura SOA. Perché non se ne può fare a meno?
§Maggio
•09/5: Le applicazioni client negli scenari d'integrazione - Parte I
•16/5: Le applicazioni client negli scenari d'integrazione - Parte II
•23/5: Interoperabilità e migrazione tra .NET e COM
§Giugno
•06/6: Smart Client. Unire il meglio di idee e tecnologie diverse
•13/6: Il dato al centro dell'informazione aziendale. Come gestirlo
•20/6: Snellire i processi aziendali gestendo il flusso di informazioni con Office
•27/6: Smart Document: la nuova faccia del documento

di Francesco BalenaSe potessi fare una survey istantanea, proverei a fare le seguenti due domande:
- Il programma che usate più frequentemente è Visual Studio?
- Avete mai usato le regular expression con il comando Find di Visual Studio?
Scommetterei che l'80% di voi risponderebbe SI alla prima domanda, ma che il 99% risponderebbe NO alla domanda successiva. Il che è alquanto bizzarro: stiamo parlando di una delle feature più potenzialmente utili dell'IDE eppure pochissimi la utilizzano o sanno addirittura che esiste.
Il vero problema è che la sintassi delle regular expression di Visual Studio è completamente differente da quella della classe Regex, quindi per usare questa feature occorrerebbe imparare un altro dialetto per le regular expression, e questo è troppo per la maggior parte degli sviluppatori. Microsoft dovrebbe usare le regex standard anche per questo comando: potrebbero farlo facilmente e in poco tempo, e senza creare problemi di compatibilità con i progetti esistenti.
In attesa che Microsoft si decida a fare questo piccola-grande innovazione, potete divertirvi con quello che avete a disposizione. Ecco alcuni esempi, tratti dal mio nuovo libro Programming Microsoft Visual Basic 2005: The Language:
:i = :z Cerca nel codice le assegnazioni di un intero a una variabile. (:i sta per un qualsiasi identificativo, :z rappresenta una costante intera). In VB (ma non in C#) trova però anche dei false match, quando una espressione contiene un operatore di uguaglianza.
:i = :q Cerca le assignazioni di una costante stringa (:q) a una variabile.
(Dim|Private|Public) :i As String Cerca le dichiarazioni di variabili e field di tipo stringa (solo VB). E' facile adattarla ad altri tipi di dati.
Dim <(:Lu(:Ll)*)+> As Cerca le dichiarazioni di variabili VB locali che usano un nome in PascalCase e che quindi violano le coding guideline di Microsoft (le variabli locali dovrebbero essere in camelCase)
^:b*'.+\n Cerca le righe di commento in VB, ossia le righe che cominciano con apostrofo. (Non considera la keyword REM.) Sostituendo l'apostrofo con // si può usare questo pattern anche in C#
Dim {:i} As (.|\n)#<\1> Evidenzia la porzione di codice tra la dichiarazione di una variabile locale e la prima occorrenza della variabile nel codice. Ripetendo questa ricerca in modo da matchare tutte le variabili locali in un metodo, si puo' controllare se vale la pena spostare la dichiarazione della variabile in modo da avvicinarla al suo primo utilizzo nel codice. (Vedi l'effetto in figura)

di Enrico SabbadinTra le varie WebCast su Visual Studio Team System, segnalo questa che mi pare la più esaustiva e piavevole per chi è agli inizi: Visual Studio Team System , fa un giro completo con il giusto livello di dettaglio su workitems, il nuovo controllo del sorgente, e le varie features di test
.. buone vacanze
di Francesco BalenaAi primi anni '90 avevo una piccola software house tutta mia, di nome Softwhale (chi è bravo con l'inglese apprezzerà il gioco di parole, spero ). Già da allora il mio pallino era scrivere tool per sviluppatori, ed avevo realizzato alcuni prodotti niente affatto male, tra cui dSwapper (una utility che abbatteva il limite dei 640K per i programmi Ms-Dos), Batch Wizard (un compilatore per file batch, che molte software house italiane hanno usato per creare procedure di installazione intelligenti), e QBKIT (una libreria di 700+ nuove funzioni per QuickBasic, incluso menu e finestre 3D). Ma uno dei maggiori successi di quegli anni fu NOWAY , un piccolo tool scritto in Assembly - come la gran parte del software che scrivevo allora - in grado di crittografare gli eseguibili Ms-Dos per evitarne il reverse engineering. All'epoca, infatti, la maggior parte dei gestionali erano scritti in Clipper, e vi erano sul mercato un paio di decompilatori in grado di ricostruire il sorgente originale, con tanti saluti alla proprietà intellettuale. L'altra caratteristica notevole di Noway era la possibilità di "legare" un eseguibile ad una macchina, in modo da proteggere dalla diffusione di copie pirata.
Come vedete, dopo una decina di anni il mondo del software ha fatto passi da gigante, ma alcune cose non sono cambiate. Anche oggi i linguaggi .NET permettono una produttività incredibile - come e più del Clipper negli anni '90 - e soffrono del medesimo difetto: chiunque può decompilare gli assembly .NET con strumenti come Reflector, e scoprire in pochi minuti un algoritmo che vi ha impegnato per settimane o mesi. Non è un caso che alcune software house hanno deciso di rinunciare ai benefici del .NET Framework pur di evitare che ciò accada.
Un paio di mesi fa stavo facendo qualche esperimento con il .NET Framework 2.0 e ho avuto una piccola illuminazione, ovvero una tecnica che permette di crittografare un assembly e di riportarlo in chiaro "al volo", al momento di caricarlo in memoria. Non intendo dilungarmi sui dettagli di questa tecnica, ma l'effetto è particolarmente interessante: poichè l'assembly su disco è sempre in forma cifrata, non è possibile decompilarlo in alcun modo, neanche con ILDASM. Insomma, mi sono detto, questo potrebbe diventare il Noway per .NET! Ecco la storia che si ripete 
Ovviamente, tra una idea e un prodotto finito passa del tempo. Prima di tutto occorreva risolvere alcuni punti potenzialmente deboli del meccanismo. Ad esempio, un hacker abbastanza in gamba potrebbe eseguire il trace del programma per capire cosa succede al caricamento, oppure potrebbe aspettare che l'assembly sia caricato "in chiaro" in memoria e salvarlo facendo un dump della memoria stessa. Sono tecniche forse fuori dalla portata di un programmatore .NET "medio" ma non di un hacker che si rispetti.
Io non sono un hacker e soprattutto non ho le conoscenze che servono per "blindare" un programma di questo tipo, quindi la cosa più saggia da fare era rivolgersi a qualcuno che queste cose le sa fare. E non credo di conoscere nessuno più indicato di Vito Plantamura, ovvero quello che io considero il "Mark Russinovich italiano". Vito non è un hacker nel senso deteriore del termine, ma conosce i meandri di Windows meglio di qualunque altro programmatore italiano io abbia conosciuto. Se volete avere una idea di cosa è in grado di fare, date una occhiata alla sua home page. Tra le tante cose che ha fatto, c'è anche BugChecker, un "clone" nientedimeno di SoftICE, un tool che fa sembrare un giocattolo il debugger di Visual Studio. Vito è nel team di Code Architects e tra non molto potrete leggerlo su questo blog o altrove su questo sito.
Comunque, in questi mesi le ricerche e gli esperimenti sono continuate ed ora siamo vicini alla fase beta vera e propria. Qualche ora fa abbiamo "battezzato" il nuovo prodotto come CodeWall.NET, seguendo il suggerimento di un gentilissimo partecipante alla WPC (dove avevamo mostrato la prima versione in anteprima). La versione 1.0 supporta soltanto applicazioni Windows Forms ed è in grado di comprimere tutti gli assembly di una solution in un unico file compresso, che quindi si puo' scaricare più velocemente. L'applicativo deve girare in modalità full-trust e quindi al momento non supportiamo ClickOnce. Se tutto va bene il prodotto finale dovrebbe essere disponibile verso i primi di gennaio.
Devo essere sincero: abbiamo rimuginato per mesi prima di decidere di rilasciare un prodotto per la protezione degli assembly .NET. Chiunque nel settore informatico sa perfettamente che non esiste la protezione inviolabile. Per quanto sia possibile blindare un eseguibile è sempre possibile arrivare a scardinare la protezione. E' una questione di abilità dell'hacker e di tempo necessario. Oppure, se si preferisce, di quanti soldi una azienda è disposta a spendere per appropriarsi dei segreti dei propri concorrenti, assoldando se necessario qualche ragazzino particolarmente versato per queste attività.
Se è vero che qualsiasi eseguibile può essere sprotetto - disponendo di tempo e denaro in abbondanza - ciò non significa che non dobbiamo neanche tentare di rendere la vita più complicata a chi vuole rubare il nostro lavoro. E' un po' lo stesso ragionamento che facciamo quando chiudiamo a chiave casa prima di uscire: sappiamo perfettamente che un malintenzionato davvero motivato - disponendo di tempo e della attrezzatura giusta - è in grado di fare saltare qualsiasi porta blindata, ma sappiamo anche che la nostra serratura potrebbe scoraggiarlo. E magari speriamo inconsciamente che il malintenzionato sposti la sua attenzione su qualche obiettivo più accessibile.
Il compito di strumenti come CodeWall.NET è di alzare la security bar tra il nostro codice e l'hacker di turno, o il cracker come sarebbe più corretto chiamare questi individui. Noi crediamo che con tutte le tecniche che abbiamo implementato - e che non possiamo discutere pubblicamente per ovvii motivi - renderemo la vita molto, ma molto difficile a questi figuri. Abbiamo passato ore e giorni a discutere su come il programma potrebbe essere attaccato e quindi siamo passati a realizzare una contromisura adeguata. In teoria anche gli assembly protetti con CodeWall.NET sono sproteggibili, ma in pratica servirà qualcuno molto bravo e con un bel po' di tempo a disposizione...
A questo punto, però, mi interessa davvero la vostra opinione. Quando realmente sentite l'esigenza di un prodotto come CodeWall.NET? e quanto i suoi limiti potrebbero indurvi a NON utilizzarlo? Lasciate pure i vostri commenti, please.
di Francesco BalenaVisual Studio 2005 è davvero pieno di piccole e piacevoli sorprese. Parlo di quelle piccole feature che rendono la vita più semplice a noi poveri programmatori, che spesso non sono neanche menzionate negli articoli che illustrano le novità di VS2005 ma che di sicuro fanno risparmiare un po' di tempo prezioso.
Copy to Output Dir: Se selezionate un file nella finestra Solution Explorer e premete F4 potete accedere alle proprietà di quel file. Una nuova proprietà, chiamata Copy to Output Dir, permette di copiare automaticamente questo file nella directory di output al termine della compilazione. In questo modo è possibile assicurarsi che il file EXE possa accedere a file di database .mdb, file XML di supporto, ecc. Lo si puo' fare anche con una macro o con un evento post-build, ma questo metodo è molto più semplice.
Unused References (VB): Una opzione della pagina References del designer My Project permette di scartare automaticamente tutti i riferimenti agli assembly esterni che non solo usati nel progetto corrente.
Test semplificato degli User Control : Se state lavorando a uno user control per Windows Forms, non occorre creare un progetto separato al solo scopo di testare il controllo. Basta rendere il progetto dello user control il progetto di startup e premere F5. Visual Studio crea al volo per voi un form che contiene il controllo in questione. Ovviamente, per un debug più completo occorre scrivere un progetto di test ad-hoc, ma questa scorciatoia è comunque molto utile nelle prime fasi dello sviluppo.
Autorecover dei sorgenti: per default, i file sorgenti sono salvati ogni 5 minuti e il backup è conservato per una settimana. E' possibile controllare le varie impostazioni di questa feature dalla pagina AutoRecover (sotto Environment) della dialog box Tools-Options.
Open Containing Folder: il menu di contesto che appare facendo right-click sulla tab del code editor permette di aprire Windows Explorer sulla directory che contiene il file in questione, oppure di copiare nella clipboard il percorso del file corrente (in modo da poterlo facilmente aprire con un altro editor).
Export and Import Settings: è finalmente possibile memorizzare e riapplicare le impostazioni correnti di Visual Studio, per non dover perdere tempo quando si installa il prodotto su un'altra macchina o quando si fa il login sulla stessa macchina ma con uno username differente.
Tracepoints: è possibile definire dei breakpoint che non bloccano l'esecuzione, ma si limitano a emettere un messaggio (che può mostrare la posizione corrente nel programma oppure il valore di variabili e proprietà della classe corrente) oppure eseguono una macro. Nel mio libro Programming Microsoft Visual Basic 2005 mostro come creare macro che interagiscono con tracepoint, creano un file di log, testano il valore di tutte le variabili locali al metodo corrente, ecc.
Custom Visualizers: Visual Studio 2005 inaugura il concetto di visualizer, ossia dei viewer custom per vedere il contenuto di oggetti in un formato appropriato. VS2005 include dei visualizer per mostrare il contenuto di un DataSet in una grid, oppure il contenuto di una stringa contenente HTML oppure XML. E' pero' possibile costruire visualizer personalizzati per altri tipi in modo relativamente facile. Nel mio libro mostro come creare un visualizer per un file di testo e per gli oggetti di tipo Bitmap e Image, e mostro anche come un visualizer può modificare il contenuto di una variabile del programma principale.
Prevedo di tornare su alcuni di questi argomenti in futuro - in particolare sui visualizer, che sono davvero interessanti. Nel frattempo potete giocare con queste piccole feature, se non le avevate già scoperte per conto vostro.
di Francesco BalenaChe settimana!
Sono tornato a casa venerdi sera, dopo cinque giorni pieni di WPC. Ero cosi cotto che ho dormito in aereo tutto il tempo, ma ovviamente ne valeva la pena. Nonostante qualche problema tecnico - dovuto al fatto che qualche giorno prima della conf il mio Dell mi ha abbandonato e ho dovuto portare tutto su un altro notebook - le mie sessioni sono andate bene, come pure tutte quelle del team di CA.
Stamattina finalmente (per modo di dire) si torna al lavoro. La prima cosa da fare è mandare i sorgenti delle demo allo staff della WPC, per farle mettere online. Provo a zippare il tutto e arrivo a 7-8 mega di roba. Il motivo è che nello zippone sono inclusi tutti i file prodotti dalla compilazione (exe, dll, obj, ecc.), di cui si puo' fare a meno quando si mandano i sorgenti. E' la solita storia, che si ripete ogni volta che devo mandare il codice per un articolo, una conferenza, o anche semplicemente quando devo passarlo a un amico via email.
Questa volta, però, invece di rimuovere manualmente ogni file, decido di investire 2 minuti (due minuti davvero, non è un modo di dire), per scrivere una piccola utility command line che fa il lavoro per me. Grazie a un overload di Directory.GetDirectories aggiunto a .NET 2.0, è possibile ottenere in un sol colpo tutte le directory in un albero di directory, quindi si tratta semplicemente di cancellare tutti i folder di nome "obj" e "bin". Se la cancellazione fallisce viene mostrato un messaggio di errore: questo puo' accadere se un eseguibile è in esecuzione e non può essere cancellato.
Imports System.IO
Module Module1 Sub Main(ByVal args() As String) ' Use current directory if no argument has been specified Dim rootDir As String = Directory.GetCurrentDirectory() If args.Length > 0 Then rootDir = args(0) ' Read all the folder names in the specified directory tree Dim dirNames() As String = Directory.GetDirectories(rootDir, "*.*", SearchOption.AllDirectories) Dim errors As Integer = 0
' Delete all the BIN and OBJ subdirectories For Each dir As String In dirNames Dim dirName As String = Path.GetFileName(dir).ToLower() If dirName = "bin" OrElse dirName = "obj" Then Try Console.Write("Deleting {0} ...", dir) Directory.Delete(dir, True) Console.WriteLine("DONE") Catch ex As Exception Console.WriteLine() Console.WriteLine(" ERROR: {0}", ex.Message) errors += 1 End Try End If Next
Console.WriteLine() If errors = 0 Then Console.WriteLine("All directories were removed successfully") Else Console.WriteLine("{0} directories couldn't be removed", errors ) End If End Sub End Module
Oltre ad essere usata dalla riga di comando, potete aggiungere questa utility al menu Tools di Visual Studio, per permettere di cancellare tutti i file prodotti dalla compilazione della soluzione corrente, usando il seguente comando
DELETEBINPATH $(SolutionDir)
dove ovviamente si suppone che DeleteBinPath sia il nome con cui avete compilato la utility.
di Francesco BalenaVisual Studio 2005 arriva con dozzine di code snippet già pronte all'uso. A dire il vero, potremmo discutere per un po' sulla qualità e l'utilità di qualcuna di queste, però ce ne sono molte davvero ben fatte. Io ad esempio uso in continuazione prop per creare proprietà pubbliche C# che "wrappano" variabili private.
La dialog box Code Snippet Manager (menu Tools) permette di ispezionare i vari snippets uno alla volta, ma stranamente non permette di creare una lista di tutti gli snippets installati, per cui uno deve guardarseli uno a uno e annotare nome, significato, e shortcut di tastiera. Mentre preparavo il capitolo 4 di Programming Microsoft Visual Basic 2005 ho scritto questo piccolo programmino usa-e-getta che decodifica l'indice degli snippets e gli elenca a video. Essendo una applicazion console, basta redirezionare l'output su file per creare un documento da usare come riferimento.
Il programma accetta in input il percorso del file SnippetIndex.xml (VB) o SnippetsIndex.xml (C#) che contiene l'indice degli snippet. (E' curioso che questo file abbia un nome differente nei due linguaggi.) Pero' lanciandolo senza argomenti utilizza il percorso di default dell'indice degli snippet VB. Un commento nel listato spiega come usare invece l'indice di default per C#.
L'output è molto spartano - solo il nome dello snippet e la sua shortcut, suddiviso in categorie - ma potete modificare facilmente il sorgente per estrarre e mostrare altri attributi. Anzi, se fate delle modifiche, mandatemele e le posto sul sito o sul blog.
Imports System.IO Imports System.Xml Imports System.Text.RegularExpressions
Module Module1 Dim snippetsPath As String Dim catNames As New Dictionary(Of String, String)
Sub Main(ByVal args() As String) ' If no argument has been provided, use default path for snippets. If args.Length = 0 Then args = New String() {"C:\Program Files\Microsoft Visual Studio 8\Vb\Snippets\1033\SnippetIndex.xml"} ' Uncomment next line to list C# snippets ' args = New String() {"C:\Program Files\Microsoft Visual Studio 8\VC#\Snippets\1033\SnippetsIndex.xml"} End If
Dim snippetsFile As String = args(0) snippetsPath = Path.GetDirectoryName(snippetsFile) ' Load the snippet index file. Dim xmlIndex As New XmlDocument() xmlIndex.Load(snippetsFile) ' We need two passes, because dirs and subdirs use a different XML element. ParseSnippetIndex(xmlIndex, "//SnippetDir") ParseSnippetIndex(xmlIndex, "//SnippetSubDir") ' Iterate over all the directories in the main snippet directory. For Each dir As String In Directory.GetDirectories(snippetsPath) ParseSnippetFolder(dir, "") Next End Sub
Sub ParseSnippetIndex(ByVal xmlIndex As XmlDocument, ByVal searchKey As String) ' Create the correspondence between relative paths and localized categories For Each xmlEl As XmlElement In xmlIndex.SelectNodes(searchKey) Dim elPath As XmlElement = DirectCast(xmlEl.SelectSingleNode("DirPath"), XmlElement) Dim elName As XmlElement = DirectCast(xmlEl.SelectSingleNode("LocalizedName"), XmlElement) catNames.Add(elPath.InnerText, elName.InnerText) Next End Sub
Sub ParseSnippetFolder(ByVal dir As String, ByVal parentCategory As String) ' Retrieve the relative name of this subdirectory. Dim relPath As String = dir.Substring(snippetsPath.Length) ' The default name for this category Dim categoryName As String = parentCategory & Path.GetFileNameWithoutExtension(dir) ' Search this relative path in the snippet index. Dim searchPath As String = "%InstallRoot%\Vb\Snippets\%LCID%" + relPath + "\" If catNames.ContainsKey(searchPath) Then ' If found, use the localized category as appears in the index file categoryName = parentCategory & catNames(searchPath) End If Console.WriteLine(categoryName.ToUpper()) ' Parse individual snippets in this directory. For Each file As String In Directory.GetFiles(dir, "*.snippet") ParseSnippetFile(file) Next ' Parse all sub-categories For Each subdir As String In Directory.GetDirectories(dir) ParseSnippetFolder(subdir, categoryName & " / ") Next End Sub
Dim reTitle As New Regex("<Title>(.+?)</Title>") Dim reShortcut As New Regex("<Shortcut>(.+?)</Shortcut>")
Sub ParseSnippetFile(ByVal snippetFile As String) Dim text As String = File.ReadAllText(snippetFile) ' We use regexes to extract information for individual snippet files. Dim maTitle As Match = reTitle.Match(text) Dim maShortcut As Match = reShortcut.Match(text) Dim title As String = maTitle.Groups(1).Value Dim shortcut As String = maShortcut.Groups(1).Value Console.WriteLine(" {0} [{1}]", title, shortcut) End Sub End Module
di Francesco BalenaDevo ammettere che a me un Watch window è sempre stata sufficiente, però per il codice che stavo debuggando oggi mi veniva comoda la possibilità di usare una seconda Watch window per un gruppo differente di valori da controllare. Nessun problema, mi sono detto: sia Visual Studio 2003 che 2005 supportano ben quattro Watch window!
Solo che nei vari menu non si trova il comando Add Watch 2, o un comando simile che crea un elemento in una Watch window differente da Watch 1. Insomma, che me ne faccio di quattro Watch window se tutti i comandi di Visual Studio agiscono sempre e soltanto sulla finestra Watch 1?
Vabbè, non ci vuole molto a capire che la cosa si puo' fare mediante drag-and-drop: basta evidenziare il nome di una variabile nel sorgente e spostarlo nella Watch window che interessa. Non solo: in questo modo è anche possible spostare le variabili anche dalle finestre Autos e Locals, e tra le varie finestre Watch. (Le operazioni di dragging effettuano sempre una copia della variabile, mai lo spostamento, quindi se necessario occorre cancellare la variabile dalla finestra Watch di provenienza.) Niente di eclatante, qundi, ma non mi ero mai accorto che il drag-and-drop funzionava anche con queste finestre.
Ecco qualche altra operazione valida con le Watch window. I primi due punti offrono due alternative al drag-and-drop per creare elementi in una Watch window qualsiasi:
- Si può creare un elemento anche eseguendo il Copy del nome di una variabile e poi usando il comando Paste in una finestra Watch.
- Facendo doppio click sulla colonna Name dell'ultima riga vuota si può inserire il nome di una variabile qualsiasi.
- Oltre a inserire il nome di una variabile è anche possibile inserire una espressione, ad esempio n+1 oppure s.ToUpper().
- Facendo doppio click sulla colonna "Value" si puo' modificare il valore.
(Questo ovviamente non è possibile se avete inserito una espressione.)
- Selezionando il comando Hexadecimal Display dal menu di contesto, è possibile visualizzare i valori esadecimali di tutte le variabili numeriche nella finestra Watch corrente.
(Questo comando agisce su tutte le finestre Watch e anche sulle finestre Autos e Locals.)
di Francesco BalenaCirca una settimana fa ho pubblicato una macro per racchiudere la selezione corrente in un blocco If...Then...Else. In questi giorni ho generalizzato il concetto, per ottenere una serie di macro in grado di effettuare il wrapping con tutte le strutture utilizzate più comunemente, sia in VB che C#: cicli, try...catch, Select/switch, #if, #region, namespace, ecc.
Per utilizzare queste macro, aggiungete il modulo qui sotto nella IDE delle Macro, tornate in Visual Studio, evidenziate nel code editor il testo che vi interessa, aprite il modulo WrappingMacros in Macro Explorer, e fate doppio click sulla macro che vi interessa applicare. Ovviamente, dopo aver applicato la macro dovrete sicuramente scrivere del codice aggiuntivo, ad esempio per scrivere la condizione della If, il nome della region, ecc.
Se poi associate una shortcut di tastiera alle macro più utili, è tutto ancora più semplice e immediato. Per sapere a colpo d'occhio quali shortcut sono disponibili e quali sono già prese da Visual Studio, leggete qui.
Imports System Imports EnvDTE
Public Module WrappinglMacros
' -------------------------------------------------------------------- ' Wrap the selected code inside IF, TRY, etc. ' --------------------------------------------------------------------
Public Sub WrapIf() WrapCode("WrapIf", "If True Then\n$sel$End If\n", "if ( true )\n{\n\t$sel$}\n") End Sub
Public Sub WrapIfElse() WrapCode("WrapIfElse", "If True Then\n$sel$Else\n\nEnd If\n", "if ( true )\n{\n\t$sel$}\nelse\n{\n}\n") End Sub
Public Sub WrapTryCatch() WrapCode("WrapTryCatch", "Try\n$sel$Catch ex As Exception\n\nEnd Try", _ "try\n{\n$sel$}\ncatch (Exception ex)\n{\n}\n") End Sub
Public Sub WrapTryFinally() WrapCode("WrapTryFinally", "Try\n$sel$Finally\n\nEnd Try", "try\n{\n$sel$}\nfinally\n{\n}\n") End Sub
Public Sub WrapTryCatchFinally() WrapCode("WrapTryCatchFinally", "Try\n$sel$Catch ex As Exception\n\nFinally\n\nEnd Try", _ "try\n{\n$sel$}\ncatch (Exception ex)\n{\n}\nfinally\n{\n}\n") End Sub
Public Sub WrapRegion() WrapCode("WrapRegion", "#Region ""RegionName""\n\n$sel$\n#End Region", _ "#region RegionaName\n\n$sel$\n#endregion") End Sub
Public Sub WrapSharpIf() WrapCode("WrapSharpIf", "#IF True Then\n\n$sel$\n#End If", "#if true\n\n$sel$\n#endif") End Sub
Public Sub WrapFor() WrapCode("WrapFor", "For index As Integer = startIndex To endIndex\n$sel$Next", _ "for (int index = startIndex; i <= endIndex; index++)\n{\n$sel$}\n") End Sub
Public Sub WrapForEach() WrapCode("WrapForEach", "For Each obj As Object In collection\n$sel$Next", _ "foreach (object obj in collection)\n{\n$sel$}\n") End Sub
Public Sub WrapWhile() WrapCode("WrapWhile", "Do While True\n$sel$Loop", "while (true)\n{\n$sel$}\n") End Sub
Public Sub WrapDoWhile() WrapCode("WrapDoWhile", "Do\n$sel$Loop While True", "do\n{\n$sel$} while ( true );\n") End Sub
Public Sub WrapNamespace() WrapCode("WrapNamespace", "Namespace NamespaceName\n$sel$End Namespace", _ "namespace NamespaceName\n{\n$sel$} // end of namespace") End Sub
Public Sub WrapSelect() WrapCode("WrapSelect", "Select Case expression\nCase 0\n$sel$Case 1\nCase Else\nEnd Select\n", _ "switch ( expression )\n{\n\tcase 0:\n\t\tbreak;\n\tcase 1:\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n}\n") End Sub
Public Sub WrapSyncLock() WrapCode("WrapIf", "SyncLock lockObject\n$sel$End SyncLock\n", "lock ( lockObject )\n{\n\t$sel$}\n") End Sub
' Helper method that replaces the selection with the specified templated text. ' The template can include $sel$ (the selected code) and escape sequences such as \r\n, \t Private Sub WrapCode(ByVal cmdName As String, ByVal vbTemplate As String, ByVal csTemplate As String) ' Determine the current language by looking at the extension of the current document. Dim doc As Document = DTE.ActiveDocument If doc Is Nothing Then Exit Sub Dim docName As String = doc.Name.ToLower() Dim sel As TextSelection = DirectCast(DTE.ActiveDocument.Selection, TextSelection) If sel Is Nothing Then Exit Sub
' Open an undo context. DTE.UndoContext.Open(cmdName) ' Retrieve the selected text, append a newline if necessary. Dim selText As String = sel.Text If Not selText.EndsWith(ControlChars.NewLine) Then selText &= ControlChars.NewLine
' Wrap the selected text, using either the VB or the C# command Dim template As String If docName.EndsWith(".vb") Then template = vbTemplate ElseIf docName.EndsWith(".cs") Then template = csTemplate End If
' Replace CR-LF, tabs, and the selected text Dim newText As String = Regex.Unescape(template).Replace("$sel$", selText) ' Reselect the text just added and format it. (Doesn't work in C#.) Dim ep As EditPoint = sel.TopPoint.CreateEditPoint() sel.Text = newText sel.MoveToPoint(ep, True) DTE.ExecuteCommand("Edit.FormatSelection") ' Close the undo context. DTE.UndoContext.Close() End Sub
End Module
di Francesco BalenaUn po' in anticipo rispetto alle previsioni, la versione Professional di Visual Studio 2005 e la versione Developer di SQL Server 2005 sono disponibili per il download a tutti gli abbonati MSDN. In teoria, almeno. Da un ora sto tentando di fare il download e ricevo sempre errore. Immagino che gli sviluppatori di tutto il mondo stiano facendo lo stesso tentativo, e una cosa del genere può mandare in tilt anche il sito meglio carrozzato.
http://msdn.microsoft.com/subscriptions/
UPDATE : al ventesimo o trentesimo tentativo il download è finalmente partito. Fra 13 o 14 ore dovrei avere il mio Visual Studio nuovo di zecca sul discone. 
di Francesco BalenaLe nuove funzioni di refactoring di C# 2.0 sono sicuramente impressionanti, come pure lo sono quelle di Refactor!, che arriverà gratis agli sviluppatori VB 2005. Ci sono però alcune funzioni di refactoring, tra le più semplici, che sono perfettamente ottenibili con una macro anche in Visual Studio 2003. Ecco ad esempio una macro che racchiude la selezione corrente in un blocco If..Then...Else
Sub WrapInIfThenElse() ' Determine the current language by looking at the extension of the current document. Dim doc As Document = DTE.ActiveDocument If doc Is Nothing Then Exit Sub
Dim docName As String = doc.Name.ToLower() Dim sel As TextSelection = DirectCast(DTE.ActiveDocument.Selection, TextSelection) If sel Is Nothing Then Exit Sub
' Open an undo context. DTE.UndoContext.Open("WrapInIfThenElse") ' Retrieve the selected text, append a newline if necessary. Dim selText As String = sel.Text If Not selText.EndsWith(ControlChars.NewLine) Then selText &= ControlChars.NewLine
' Embed the selected text in an If...Then...Else block. ' Replace the selection with the new text and format the document. Dim newText As String If docName.EndsWith(".vb") Then newText = String.Format("If True Then{0}{1}Else{0}{0}End If{0}", _ ControlChars.NewLine, selText) ElseIf docName.EndsWith(".cs") Then ' Replace the selection with newText = String.Format("if ( true ){0}{{ {0}{1} }}{0}else{0}{{ {0} }}{0}", _ ControlChars.NewLine, selText) End If
' Reselect the text just added and format it. (Doesn't work in C#.) Dim ep As EditPoint = sel.TopPoint.CreateEditPoint() sel.Text = newText sel.MoveToPoint(ep, True) DTE.ExecuteCommand("Edit.FormatSelection") ' Close the undo context. DTE.UndoContext.Close() End Sub
La macro funziona molto bene in Visual Basic, un po' meno bene in C#. In particolare, per qualche motivo il comando Edit.FormatSelection non funziona in questo linguaggio, quindi occorrerà riselezionare il testo e richiamarlo manualmente, dal sottomenu Advanced del menu Edit oppure premendo i tasti Ctrl+K, Ctrl+F.
Modificando solo un paio di righe è facile creare numerose macro con funzionalità simili, per eseguire il wrapping all'interno di strutture For, For Each, Try...Catch...Finally, e cosi' via.
Una piccola macro come questa certo non moltiplicherà la vostra produttività in modo esponenziale, ma avercela sempre a portata di mano fa risparmiare 3-4 secondi ogni volta. Usatela 15-20 volte al giorno e alla fine della giornata potrete rimanere un minuto in più alla macchina del caffè, senza troppi sensi di colpa 
di Marco BellinasoOggi ho speso un po' di tempo per fare il porting dalla beta2 alla RC1 di un sito ASP.NET 2.0. Non ci sono stati grandi problemi: se cambia il nome di una proprietà si stà veramente presto a capire qual è il nome nuovo, anche consultanto questa pagina. Ci sono però un paio di cambiamenti significativi la cui soluzione potrebbe non essere immediata, e che quindi ho deciso valesse la pena riportare nel blog. Io mi sono accorto di questi 2 cambiamenti solo ora, perchè le CTP intermedie tra la beta2 e la RC1 non sono mai riuscito ad installarle completamente con successo. Quindi può darsi che le cose fossero cambiate già prima.
Del primo cambiamento me ne sono accorto ricevendo la seguente eccezione all'esecuzione del codice per ottenere il profilo di un utente (quello corrente o un altro): {"Procedure or Function 'aspnet_Profile_GetProperties' expects parameter '@TimeZoneAdjustment', which was not supplied."}. Dopo aver cercato su Google per qualche minuto senza esito, mi sono creato un nuovo progettino web con la RC1 e ho controllato che i profili funzionassero. Il responso è stato ovviamente positivo. Allora sono andato a controllare la sproc incriminata, aspnet_Profile_GetProperties, nel DB che avevo nel progetto beta2, e nel progetto creato ex-novo con la RC1. Nel primo caso la sproc ha un terzo parametro chiamato @TimeZoneAdjustment, nel secondo caso il terzo parametro è @CurrentTimeUtc. E' quindi stato ovvio che il motivo dell'eccezione è che il codice della classe SqlProfileProvider aggiornata chiamava la stored procedure passando @CurrentTimeUtc, mentre la vecchia sproc presente nel DB si aspettava @TimeZoneAdjustment. La soluzione consiste nell'eseguire il wizard di aspnet_regsql.exe, selezionando l'opzione per eliminare il supporto ai servizi di ASP.NET 2.0 (membership, profili, logging, caching, personalization) dal database in questione. Fatto ciò si esegue nuovamente il tool riaggiungendo il supporto per tutti quelle funzionalità, e quindi di fatto ricreando tutti gli oggetti necessari per il loro funzionamento (tabelle, sproc, trigger), con lo schema aggiornato. A parte aver perso le informazioni sui pochi account di test che avevo creato (erano 4 record, quindi non valeva neanche la pena fare il backup) il risultato è stato perfetto.
Il secondo problema è che tutti i controlli ObjectDataSource collegati a un domain object e usati come data source dai vari controlli GridView e DetailsView sollevavano eccezione all'esecuzione dei comandi Update e Delete. Il problema qui era che nella beta2 i valori originali del record da cancellare/aggiornare (quindi ad esempio l'ID che identifica il record) venivano passati a parametri del metodo chiamati original_{NomeFieldQui}, ad esempio original_ID. Il prefisso poteva anche essere cambiato tramite la proprieta OldValuesParameterFormatString dell'ObjectDataSource, che per default era appunto impostata su "original_{0}". Tutte le mie classi usavano quindi questa convenzione per ricevere correttamente l'ID chiave nei metodi Update e Delete. Ora nella RC1 il valore di default di questa proprietà è {0}, ovvero il nome del campo senza più nessun prefisso. Ne consegue che l'ObjectDataSource non cercherà più un parametro nominato original_ID nella firma del metodo, ma ID e basta. Non lo trova e solleva eccezione. Le soluzioni possibili sono 2: o rinominate i parametri dei vostri metodi togliendo il prefisso (e lasciando quindi "id" o "ID", il controllo non è case-sensitive) oppure ripristinate il valore di OldValuesParameterFormatString su "original_{0}". Io ho preferito seguire la prima opzione per essere in linea con quanto fa di default VS.NET, e la cosa non ha preso comunque troppo tempo. Questa modifica al controllo ObjectDataSource è stata suggerita dal feedback di molti sviluppatori che hanno lavorato con le beta2, e che trovavano poco intuitivo dover nominare i parametri dei loro metodi con quel prefisso. Ecco l'annuncio semi-ufficiale da uno dei componenti del team di ASP.NET. Io sono in effetti d'accordo! Se dovesse comunque esserci la necessità di ottenere in input sia il valore corrente che quello originale di un campo, sarà comunque sempre possibile reimpostare un qualche prefisso per OldValuesParameterFormatString e avere il meccanismo funzionante esattamente come prima.
Tutto sommato il porting dalla beta2 alla RC1 è stato molto semplice, non ho fatto neanche in tempo a cominciare ad imprecare Sempre che non ora spuntino sorprese poco piacevoli...ma sono ottimista!
di Francesco BalenaMi capita spesso di dover copiare pezzi di un testo sotto forma di commento nei miei sorgenti. Non è una operazione difficile, però è pur sempre una perdita di tempo, perchè spesso non si può semplicemente eseguire il copia e incolla e poi il comando Edit-Comment Selection perchè - almeno in VB - l'editor di Visual Studio cerca di interpretare il testo come codice e quindi ne rovina la formattazione. A questo si aggiunge il fatto che spesso sono costretto a rivedere tutte le andate-a-capo nel testo per evitare righe troppo lunghe, perchè i listati che appaiono nei libri non possono essere più lunghi di N caratteri (tipicamente 92 caratteri, per i libri Microsoft Press). Insomma, una bella seccatura.
Oggi ho deciso di porre fine a questa perdita di tempo, scrivendo una macro che faccia questo lavoro al mio posto. E' un piccolo modo per aumentare la produttività e concentrarsi sulle cose davvero importanti. Se anche a voi piacciono i listati ordinati, sono certo che la troverete utile.
La prima difficoltà in cui mi sono imbattuto è il fatto che, per qualche arcano motivo, il metodo Clipboard.GetObjectData restituisce sempre Nothing quando lo si chiama da una macro, quindi non è possibile usare quel metodo per leggere il contenuto della clipboard. Per qualche minuto ho accarezzato l'idea di lavorare direttamente con le API oppure di scrivere una DLL che eseguisse questo compito, poi ho trovato la classica soluzione a-ha!:
' Retrieve the text in the clipboard
Dim tb As New TextBox
tb.Multiline = True
tb.WordWrap = False
tb.ScrollBars = ScrollBars.Both
tb.Paste()
Dim text As String = tb.Text
Questo codice funziona quasi sempre bene. Ogni tanto, però, ho notato che il metodo Paste fallisce con un messaggio di errore un po' criptico: "Class already exists". Non riesco a spiegarmi il motivo...e tutto sommato non voglio neanche saperlo. Ho notato però che tutto funziona bene se l'editor delle macro è chiuso, quindi nell'uso normale non ci dovrebbero essere problemi. Se però incappate una volta in questo errore, da quel momento in poi la macro andrà sempre in errore. L'unico modo per evitarlo è uscire e rientrare Visual Studio. Come ho detto, accade solo durante lo sviluppo delle macro, quindi non è un problema davvero fastidioso.
Ecco il sorgente completo della macro che esegui il paste del contenuto corrente della clipboard sotto forma di commento:
Imports System.Text.RegularExpressions
Module UsefulMacros
Public Sub PasteAsComment()
PasteAsComment("80")
End Sub
Public Sub PasteAsComment(ByVal lineLength As String)
Dim maxLength As Integer = CInt(lineLength)
' Determine the language by looking at the extension of the current document.
Dim doc As Document = DTE.ActiveDocument
If doc Is Nothing Then Exit Sub
Dim docName As String = doc.Name.ToLower()
' Determine the caret position
Dim sel As TextSelection = DirectCast(DTE.ActiveDocument.Selection, TextSelection)
Dim ep As EditPoint = sel.ActivePoint.CreateEditPoint()
' Determine the comment prefix
Dim commentPrefix As String = "" 'Space(ep.DisplayColumn)
If docName.EndsWith(".vb") Then
commentPrefix &= "' "
ElseIf docName.EndsWith(".cs") Then
commentPrefix &= "// "
Else
' Unsupported language
Return
End If
' Retrieve the text in the clipboard
Dim tb As New TextBox
tb.Multiline = True
tb.WordWrap = False
tb.ScrollBars = ScrollBars.Both
tb.Paste()
Dim text As String = tb.Text
' Split in lines not longer than MaxLength
Dim result As String = commentPrefix
Dim currLineLength As Integer = commentPrefix.Length
For Each m As Match In Regex.Matches(text, "\S+\s*")
If currLineLength + m.Length > maxLength Then
result &= ControlChars.CrLf
result &= commentPrefix
currLineLength = commentPrefix.Length
End If
result &= m.Value
currLineLength += m.Length
If m.Value.IndexOf(ControlChars.CrLf) > 0 Then
result &= commentPrefix
currLineLength = commentPrefix.Length
End If
Next
result &= ControlChars.CrLf
sel.Insert(result)
End Sub
End Module
Come vedete le macro sono in realtà due. La versione senza argomenti crea righe di commento lunghe 80 caratteri: presumibilmente è la versione che userete probabilmente più spesso e vi conviene associarla a uno shortcut di tastiera. Al contrario, la versione con argomento può essere usata solo dalla finestra di comando per eseguire il paste con word wrapping alla colonna che desiderate voi. Ecco come potete eseguire il seguente comando dalla finestra Immediate per eseguire il paste con righe non più lunghe di 60 caratteri
Macros.MyMacros.UsefulMacros.PasteAsComment 60
Molto probabilmente vi stuferete molto presto di scrivere tutto questi caratteri. In tal caso, vi conviene associare un alias - ad esempio PasteCom - al comando, in questo modo:
alias PasteCom Macros.MyMacros.UsefulMacros.PasteAsComment
Dopo la creazione dell'alias, i caratteri da digitare sono molti di meno:
PasteCom 60
Questo è tutto per oggi. Ci vediamo alla prossima macro 
UPDATE: Andrea Ferendeles ha suggerito un modo per leggere il contenuto della clipboard da una macro meno macchinoso del mio e che non soffre dei problemi citati. (vedere i commenti). Ho ritoccato il codice di Andrea per adeguarlo alla macro, che ora è diventata
Public Sub PasteAsComment() PasteAsComment("80") End Sub
Public Sub PasteAsComment(ByVal lineLength As String) Dim maxLength As Integer = CInt(lineLength) ' Read the text in the clipbard, through the Selection.Paste method. ' (Thanks to Andrea Ferendeles for the suggestion.) Dim sel As TextSelection = DirectCast(DTE.ActiveDocument.Selection, TextSelection) Dim sp As EditPoint = sel.ActivePoint.CreateEditPoint() sel.Paste() sel.MoveToPoint(sp, True)
' Read this text, then delete it Dim text As String = sel.Text sel.Delete()
' Split in lines not longer than MaxLength Dim result As String = "" Dim currLineLength As Integer = 0 For Each m As Match In Regex.Matches(text, "\S+\s*") If currLineLength + m.Length > maxLength Then result &= ControlChars.CrLf currLineLength = 0 End If result &= m.Value currLineLength += m.Length If m.Value.IndexOf(ControlChars.CrLf) > 0 Then currLineLength = 0 End If Next result &= ControlChars.CrLf
' Paste the text in the code editor sp = sel.ActivePoint.CreateEditPoint() sel.Insert(result) sel.MoveToPoint(sp, True)
' Comment and reformat it DTE.ExecuteCommand("Edit.CommentSelection") sel.SmartFormat() End Sub
Ho anche preso da Andrea l'idea di usare il comando DTE.ExecuteCommand per creare i commenti, che funziona con tutti i linguaggi supportati da Visual Studio. In questo modo, però, i caratteri dei commenti non sono considerati ai fini della larghezza massima delle righe, a differenza della macro originale, ma non credo sia un gran problema, no?
di Francesco BalenaIeri ho postato una macro che converte i field in properties. Qualche minuto fa ho rivisto il codice per supportare anche i campi marcati con readonly. Se applicate la macro a tali campi, otterrete (ovviamente!) delle proprietà a sola lettura. In VS2005 potreste anche modificare la stringa assegnata alla variabile repPatternReadonly per generare proprietà con un blocco set privato, in modo da avere una proprietà a sola lettura se vista dall'esterno della classe ma assegnabile dal codice che gira nella classe stessa.
di Francesco BalenaUna cosa che mi stupisce sempre molto è vedere come molti programmatori passino ore a discutere se sia più produttivo VB o C# o Java - magari discettando sulle feature relativamente "minori" del proprio linguaggio - e poi non conoscano a fondo proprio il tool con cui passano la maggior parte del tempo, ovvero l'IDE in cui scrivono e testano il codice. In particolare, ci sono decine e decine di feature di Visual Studio che nella maggior parte dei casi sono sconosciute ai più. Dopo tanti anni, capita anche a me di scoprirne continuamente di nuove.
Il modo migliore per aumentare la produttività con Visual Studio è imparare a scrivere delle macro per automatizzare i compiti più ripetitivi. Certo, ci sono sul mercato tantissimi add-in - anche freeware - che permettono di automatizzare dei compiti ripetitivi, ma capita raramente che facciano esattamente quello che vogliamo. Se volete davvero padroneggiare Visual Studio, occorre proprio rimboccarsi le maniche e imparare a scrivere un po' di macro. Nei casi più semplici, potete semplicemente usare il registratore di macro e modificare poi il codice generato.
Ad esempio, io spesso nei miei prototipi di classe uso dei campi pubblici, ma quando poi occorre scrivere del codice "di produzione" passo un sacco di tempo a convertire il campo in una variabile privata "wrappata" da una proprietà pubblica. Per capirci, parto con questo codice nel prototipo:
' The name of the element
Public Name As String = "Francesco"
e arrivo a questa proprietà nella applicazione finita
' The name of the element Private m_Name As String = "Francesco"
Public Property Name() As String Get Return m_Name End Get Set(ByVal Value As String) m_Name = Value End Set End Property
Un giorno finalmente ho deciso di scrivere una macro che automatizza questo lavoro. Ci ho perso una mezz'ora, ma il tempo che mi ha fatto risparmiare da allora è davvero incalcolabile. Per risparmiarvi anche quella mezz'ora (che potrebbe essere un po' più di mezz'ora se non avete dimestichezza con il modello a oggetti di Visual Studio e con le regular expression), ecco a voi la macro.
Imports EnvDTE Imports System.Text.RegularExpressions
Public Module CodeArchitectsMacros Dim repPattern As String Dim repPatternReadOnly As String
Sub ConvertVariables() ' Determine current language by looking at the extension of the current document. Dim doc As Document = DTE.ActiveDocument If doc Is Nothing Then Exit Sub Dim docName As String = doc.Name.ToLower()
' Read all the text lines touched by the selection. Dim sel As TextSelection = CType(DTE.ActiveDocument.Selection, TextSelection) Dim ed1 As EditPoint = sel.AnchorPoint.CreateEditPoint() ed1.EndOfLine() : ed1.StartOfLine() : ed1.StartOfLine() Dim ed2 As EditPoint = sel.BottomPoint.CreateEditPoint() ed2.EndOfLine() Dim text As String = ed1.GetText(ed2)
' The find and replacement pattern depend on the current language. Dim findPattern As String If docName.EndsWith(".vb") Then findPattern = "(?<indent>[\t ]+)Public\s+(?<static>Shared\s+)?(?<readonly>ReadOnly\s+)?" _ & "(?<name>\w+)\s+As\s+(?<type>\S+)(?<init>.*?)\n" ' {0}=property name, {1}=property type, {2}=static keyword, {3} initvalue, ' {4}=CR-LF, {5}=Tab, {6}=indent repPattern = "{6}Private {2}m_{0} As {1}{3}{4}" _ & "{6}Public {2}Property {0}() As {1}{4}" _ & "{6}{5}Get{4}" _ & "{6}{5}{5}Return m_{0}{4}" _ & "{6}{5}End Get{4}" _ & "{6}{5}Set(ByVal Value As {1}){4}" _ & "{6}{5}{5}m_{0} = Value{4}" _ & "{6}{5}End Set{4}" _ & "{6}End Property{4}{4}" repPatternReadOnly = "{6}Private {2}ReadOnly m_{0} As {1}{3}{4}" _ & "{6}Public ReadOnly {2}Property {0}() As {1}{4}" _ & "{6}{5}Get{4}" _ & "{6}{5}{5}Return m_{0}{4}" _ & "{6}{5}End Get{4}" _ & "{6}End Property{4}{4}" ElseIf docName.EndsWith(".cs") Then ' Notice the (?.*;) element is needed to ensure that public fields are matched, ' but public properties aren't findPattern = "(?<indent>[\t ]+)public\s+(?<static>static\s+)?(?<readonly>readonly\s+)?" _ "(?<type>\S+)\s+(?<name>\w+)(?=.*;)(?<init>.*?)\n" ' {0}=property name, {1}=property type, {2}=static keyword, {3} initvalue, ' {4}=CR-LF, {5}=Tab, {6}=indent repPattern = "{6}private {2}{1} m_{0}{3}{4}" _ & "{6}public {2}{1} {0}{4}" _ & "{6}{{{4}" _ & "{6}{5}get {{ return m_{0}; }}{4}" _ & "{6}{5}set {{ m_{0} = value; }}{4}" _ & "{6}}}{4}{4}" repPatternReadOnly = "{6}private {2}readonly {1} m_{0}{3}{4}" _ & "{6}public {2}{1} {0}{4}" _ & "{6}{{{4}" _ & "{6}{5}get {{ return m_{0}; }}{4}" _ & "{6}}}{4}{4}" End If
' Replace the text. Add a trailing CR-LF but remove it later. Dim replaceText As String = Regex.Replace(text + ControlChars.CrLf, findPattern, _ AddressOf ReplaceWithProperty) ed1.ReplaceText(ed2, replaceText.Substring(0, replaceText.Length - 2), 0) End Sub
' Private callback function for the Replace method Private Function ReplaceWithProperty(ByVal m As Match) As String Dim pattern As String = repPattern If m.Groups("readonly").Length > 0 Then pattern = repPatternReadOnly Return String.Format(pattern, m.Groups("name").Value, m.Groups("type").Value, _ m.Groups("static").Value, m.Groups("init").Value, ControlChars.CrLf, _ ControlChars.Tab, m.Groups("indent").Value) End Function
End Module
Non fatevi ingannare dal numero limitato di istruzioni in questa macro. Infatti, grazie alle regular expression usate a dovere, la macro funziona sia in VB che in C#, permette di convertire una o più variabili in un solo colpo, preserva il valore iniziale e l'attributo Shared/static, e preserva anche qualsiasi istruzione che dovesse trovarsi in mezzo alle dichiarazioni. In pratica, quindi potete anche evidenziare il codice di una intera classe e convertire tutte le sue variabili pubbliche in proprietà, con un solo click del mouse! 
Notate che la macro crea automaticamente una variabile che si chiama m_propname; ovviamente potete modificare l'assegnazione a repPattern per utilizzare la naming convention che preferite. Oppure i programmatori C# possono modificare il codice per generare i blocchi get/set spalmati su più righe. (A me non piace sprecare spazio nell'editor se non è realmente necessario.)
UPDATE: Ho aggiornato la macro per tenere conto delle variabili marcate con le keyword ReadOnly, che ovviamente generano proprietà a sola lettura. In VS2005 si può modificare il codice assegnato a repPatternReadonly per generare proprietà con un blocco set di tipo privato.
Per installare e usare questa macro seguite i passi seguenti:
1) usate il comando Tools-Macros-Macro IDE (oppure premete Alt+F11) per mostrare l'IDE per le macro 2) Nel macro IDE, selezionate il progetto MyMacros, poi usate il comando Projects-Add Module per creare un nuovo modulo chiamato CodeArchitectsMacros, poi incollate il codice precedente nel nuovo modulo 3) tornate in Visual Studio, e mostrare il Macro Explorer usando il comando Tools-Macros-Macro Explorer (oppure premete Alt+F8); nella finestra Macro Explorer, espandete il nodo MyMacros e poi espandete il modulo CodeArchitectsMacros 4) evidenziate nel codice VB o C# una o più dichiarazioni di variabili pubbliche, poi fate doppio click sul metodo ConvertVariables per trasformarle in proprietà. 5) opzionalmente, nella dialog Tools-Options assegnate una shortcut di tastiera alla macro, in modo da poterla richiamare senza dover prima aprire il Macro Explorer. Ovviamente potete anche assegnare la macro a un pulsante sulla toolbar di Visual Studio.
Se lavorate molto con classi e proprietà, fatemi un favore: installate la macro e fra un mese fatemi sapere quanto tempo vi ha fatto risparmiare. E fatemi anche sapere se vi piacerebbe che pubblicassi altri productivity enhancement di questo tipo.
di Giuseppe Dimauro
J
Problema: docking di controlli .NET direttamente nella client area di Outlook con VSTO per Visual Studio 2005
Il file contenente il codice sorgente: HtmlViewModified.zip (256.37 KB)
Impegnato per conto di un cliente che sta ricrivendo una serie di applicazioni direttamente dentro Office System con .NET 2.0 e VS2005 – e Outlook 2003 in particolare - mi sono imbattuto in un “piccolissimo” problema non di poco conto. Benche’ con gli altri prodotti di Office sia particolarmente semplice mostrare e usare form di ogni genere preparate in .NET, con Outlook 2003 ci siamo subito imbattuti in una serie di limiti che inizialmente sembravano insuperabili e decisamente antipatici. Per la precisione, a prima vista sembra che sia impossibile “dockare” le proprie form .NET all’interno dell’area client principale di lavoro di Outlook (l’area della inbox per intenderci) per scrivere applicazioni di produttivita’ utilizzando .NET, direttamente dentro Outlook. Pero’ ... con un po’ di fortuna e di intuito posso ora dire che l’empasse e’ durata relativamente poco. Infatti scaricato il preziosissimo esempio HtmlView disponibile sul sito di MSDN, che mostra come fare un po’ di report con del HTML plasmato via .NET, l’idea di ospitare le form (controlli windows form) .NET all’interno del HTML viewer (e’ il controllo del browser IE embedded dentro outlook) si e’ fatta subito strada. Devo ammettere che la mia bassissima conoscenza di HTML (che proprio non mi entra in testa - che ci volete fare) e’ stata, alla fine, la parte piu’ complessa del tutto. Per il resto il lavoro di inserimento delle form (controlli .NET) dentro Outlook e’ stato tutto in discesa e senza troppi problemi o intoppi. Descrivo brevemente per punti una serie di considerazioni e consigli da seguire per studiare il materiale allegato che mostra la soluzione del problema:
- aggiornate la connection string nel .config che fa una piccola query sul db northwind per mostrare un diagramma a torte dentro un report embedded nella form schiacciando uno dei due pulsanti che troverete in testa alla vista dentro Outlook dopo aver lanciato l’applicazione e selezionata la cartella HtmlView figlia della cartella Inbox.
- la classe BaseActiveXContainer (che ho copiato da qualche parte e modificato – l’autore mi perdoni per questo) contiene del pratico codice per registrare i controlli .net come componenti COM
- Generate tutte le volte un nuovo GUID per ogni nuovo controllo. Non usate la tecnica CCP (Cut Copy e Paste J - Copyright del mio amico Pierpaolo R.) con gli occhi bendati. Brutte sorprese vi aspettano.
- Nel file AssemblyInfo.cs (aggiunto a manina perche’ in disuso con vs2005 – decideremo una best practice spero tra pochissimo ...) ho inserito degli attributi assembly wide per evitare problemi di security per caricare dll che non sopportano di essere chiamate da assembly “partially trusted”.Senza, molte LoadAssembly dinamiche rischiano di dare parecchi problemi.
[assembly: AllowPartiallyTrustedCallers]
[assembly: FileIOPermission(SecurityAction.RequestMinimum, Unrestricted = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, Execution = true)]
[assembly: RegistryPermission(SecurityAction.RequestMinimum, Unrestricted = true)]
[assembly: UIPermission(SecurityAction.RequestMinimum, Unrestricted = true)]
- In testa alla classe HtmlViewContainer trovate una serie di attributi che vi permetteranno di riesporre attravers COM i vostri controlli .NET da “agganciare” dentro Office. La stessa classe contiene una serie di proprieta’ statiche che espongono globalmente nella applicazione i puntatori alle istanze di alcuni oggetti importanti di Outlook per interoperare con lo stesso con interfacce duali COM per supportare Automation.
- Il file “.htm” del progetto allegato mostra come invocare metodi dell’oggetto ospitato dal HTML, che ospita il controllo .NET nella pagina, via jscript e automation.
- Preparatevi mentalmente ad usare caspol o l'utility presente negli administrative tools per dare full trust ad eventuali DLL esterne bisognose di essere trattate in tal modo. Sappiate che il vostro assembly dentro la sandbox di Outlook e partially trusted. Vi consiglio di firmare digitalmente le vostre DLL e fare full trust su machine con le strong name degli assembly o direttamente un certificato buono.
- altre ed eventuali ... prossimamente :) stay tuned
Una piccola schermata che mostra quello che si puo' fare dentro Outlook con .NET e VSTO per VS2005 completato in treno mentre tornavo a casa :). Nel codice trovate tutto quello che serve per far parlare il vostro controllo con Outlook dall'interno dell'explorer html di Outlook.

Enjoy !
Sto lavorando su dei proof of concept per Microsoft per Office Word ed Excel avanzatissimi. Spero di condividere al piu' presto con voi il materiale che sto producendo.
Giuseppe
di Francesco BalenaIn un post del maggio scorso mi lamentavo del fatto che in Visual Studio 2005, scrivendo Implements IDisposable nella dichiarazione di una classe si otteneva il pattern Dispose-Finalize completo. Un sacco di codice, ma soprattutto un codice sbagliato, in quanto una classe disposable in genere NON deve implementare il metodo Finalize, in quanto il metodo Finalize serve solo se la classe crea e utilizza risorse unmanaged.
Le classi dotate di Finalize richiedono qualche ciclo di CPU in più durante l'istanziazione, ma questo non era il problema principale a mio avviso. Il fatto che Visual Studio creasse automaticamente codice errato mi dava un fastidio quasi fisico: chi avrà mai preso questo decisione a Redmond?
Beh, evidentemente non sono stato l'unico a lamentarsi, perchè ho appena scoperto - con molto piacere - che questa "feature" è stata rimossa nella CTP di Agosto (e immagino anche nella RC). Ora quando digitate Implements IDisposable, VS2005 risponde creando il codice seguente:
Class FooBar Implements IDisposable
Private disposedValue As Boolean = False ' To detect redundant calls
' IDisposable Protected Overridable Sub Dispose(ByVal disposing As Boolean) If Not Me.disposedValue Then If disposing Then ' TODO: free unmanaged resources when explicitly called End If ' TODO: free shared unmanaged resources End If Me.disposedValue = True End Sub
#Region " IDisposable Support "
' This code added by Visual Basic to correctly implement the disposable pattern. Public Sub Dispose() Implements IDisposable.Dispose ' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above. Dispose(True) GC.SuppressFinalize(Me) End Sub
#End Region End Class
E' bello, una volta tanto, poter dire a posteriori "lo avevo detto io!" 
di Francesco BalenaSto correggendo il capitolo dedicato al namespace My, e sto aggiungendo alcuni dettagli che avevo tralasciato nella prima stesura, come la creazione di custom setting provider (per salvare i settings su altri medium oltre al classico file di configurazione, ad esempio un database) e la possibilità di eseguire il binding delle proprietà di un controllo con le impostazioni utente. I custom setting provider sono abbastanza complessi e interessano un numero relativamente ristretto di programmatori, mentre il binding dei setting è un argomento decisamente molto più semplice e che non mancherà di suscitare interesse di chiunque lavori con i Windows Forms. Insomma, l'argomento ideale per un post sul blog di dotnet2themax.
Ho trovato molti articoli e post sull'oggetto My.Settings di Visual Basic 2005 (nonchè dell'omologo Settings di C#), ma quasi tutti omettono di sottolineare il fatto che è possibile eseguire il binding di uno user setting con una proprietà di un form, incluso le proprietà Size e Location. Questa feature permette - tra le tante cose - di ritrovare ciascun form della applicazione nella posizione e nella forma in cui l'utente lo aveva lasciato la volta precedente (nella stessa sessione di lavoro o in una sessione precedente). L'infrastruttura di .NET 2.0 si prende carico di assegnare la proprietà quando il form viene caricato e di salvarla nel file di configurazione quando la proprietà è modificata.

Figura 1: Il designer di Visual Studio 2005 permette di definire settings a livello utente e applicazione.
|

Figura 2: Eseguire il binding di una proprietà con una impostazione utente.
|
Il bello è che non dovete scrivere neanche mezza riga di codice. Infatti, è sufficiente definire le proprietà in questione nella pagina Settings del designer My Project (Visual Basic) oppure Properties (C#), ad esempio MainFormLocation e MainFormSize (Figura 1); è essenziale che lo scope di queste impostazioni sia User, poichè le impostazioni di tipo Application non sono modificabili. A questo punto potete selezionare il form, passare alla finestra Properties, aprire la sezione (Application Settings), cliccare sulla freccia accanto al nome delle proprietà ClientSize e Location, e selezionare lo user setting da mettere in binding. Se non avete ancora create il setting in questione, basta cliccare sull'elemento New. (Figure 2)
Come ho già accennato, il dettaglio notevole è che il valore di queste impostazioni viene aggiornato automaticamente quando spostate e ridimensionate il form. Ovviamente si possono mettere in binding altre proprietà, ad esempio Text, BackColor, ecc. Facendo la stessa cosa per tutti i form della applicazione abbiamo a disposizione un meccanismo di persistenza delle impostazioni dei form semplice e potente, ancora una volta senza scrivere codice!
Ovviamente è possibile fare lo stesso con le proprietà dei singoli controlli. Non tutte le proprietà sono in grado però di notificare a .NET il fatto che sono state modificate. Perchè ciò avvenga il controllo deve implementare l'interfaccia IBindableComponent e deve implementare un evento XxxxChanged per la singola proprietà, oppure implementare la nuova interface INotifyPropertyChanged. La maggior parte dei controlli Windows Forms implementano queste interfacce, ma non tutti. Ad esempio, il controllo ToolStripItem non la implementa. In questo caso la proprietà sarà impostata correttamente quando il form viene mostrato, ma il valore del setting deve essere aggiornato via codice. |
di Giuseppe DimauroAlcuni sample recuperabili via Internet per provare e studiare VSTO (Visual Studio Tools for Office - pronunciato VISTO) per Outlook potrebbero dare problemi di compilazione. Io ho scaricato ad esempio questi sample da msdn.microsoft.com e ho dovuto apportare le seguenti modifiche nell'evento di startup utilizzando il metodo protetto GetPrimaryControl per sistemare il tutto:
Prima della modifica:
private void ThisApplication_Startup(object sender, System.EventArgs e) { // Initialize the event tracker object. _eventTracker = new EventTracker(this); // Create custom menu items. CreateMenu(); }
Dopo la modifica, utilizzando il metodo GetPrimaryControl:
private void ThisApplication_Startup(object sender, System.EventArgs e) { // Initialize the event tracker object. _eventTracker = new EventTracker(this.GetPrimaryControl()); // Create custom menu items. CreateMenu(); }
Vi consiglio vivamente di dare una occhiata a questa tecnologia perchè i risultati sono veramente notevoli. Ovviamente le stesse modifiche valgono anche per gli esempi in VB.
di Francesco BalenaOggi riflettevo sul fatto che ho cominciato la mia carriera di speaker a conferenze per programmatori esattamente 10 anni fa, il 27 ottobre 1995 al VB Forum organizzato da Edizioni Infomedia e la rivista Visual Basic Journal, che avevo da poco fondato. Come tutte le prime volte, ero super-emozionato, parlavo troppo velocemente, avevo un volume discontinuo, non sapevo dove tenere le mani, ecc. Dopo dieci anni sono sicuramente migliorato un bel po' (ma ho ancora margini per migliorare!) e credo di poter passare qualche consiglio a chi comincia solo ora.
In questo post, però, non mi preme offrire una lista di consigli per diventare un bravo oratore e mi limiterò invece a dare qualche spunto di riflessione su come preparare al meglio le demo con Visual Studio. Ci sono tante piccole cose che è possibile fare in questo campo e che relativamente pochi speaker fanno. Inoltre, si tratta di piccoli consigli che possono essere utili anche a coloro che conducono corsi di programmazione in aula, che sono certamente un numero maggiore di coloro che hanno la fortuna di salire su un palco a parlare davanti a centinaia di persone.
Avevo preparato questa lista qualche anno fa, ad uso e consume del team di Code Architects, che oramai sono speaker collaudati e non ne hanno più bisogno. La lista è divisa in due parti: la prima dedicata alla fase di preparazione della sessione, la seconda con consigli su come condurre le demo durante la sessione.
Prima della sessione
Impostare font leggibili per l'editor di codice Non tutti gli spettatori siedono in prima file o hanno la vista delle aquile. È preferibile impostare la dimensione del font ad almeno 14-16 punti. Per aumentare la quantità di codice visibile sullo schermo si puo' utilizzare un font proporzionale, ad esempio Arial Black.
Modificare il colore del testo selezionato Di default Visual Studio mostra il testo selezionato con caratteri bianchi su sfondo blu scuro, ma il risultato è molto poco leggibile durante le presentazioni. È molto meglio mantenere il colore nero per il testo e usare un colore chiaro (ad esempio ciano) per lo sfondo.
Mantenere i colori di default A parte le modifiche indicate nei punti precedenti, evitare di modificare i colori di default usati da Visual Studio. La stragrande maggioranza degli sviluppatori si aspetta che i breakpoint siano marcati in rosso, l'istruzione attualmente in esecuzione dovrebbe essere in giallo, e così via. E' anche opportuno usare lo schema di default per i colori di Windows, quello con la barra dei titoli in blu (o al massimo il Silver, quello con la barra dei titoli in grigio).
Usare font più grandi per l'interfaccia utente Nel creare una applicazione Windows Form o Web Form, utilizzare un font più grande del solito per i vari elementi della interfaccia utente, sia nelle applicazioni demo preparate in anticipo, sia per quelle create al volo. È sufficiente ricordare di modificare il font del form subito dopo averlo creato, in modo che tutti i controlli sul form si adattino alla nuova dimensione.
Lunghezza delle righe di codice Negli esempi di codice che si intende mostrare durante la sessione è opportuno spezzare le righe ad una lunghezza tale da non rendere necessario l'uso della scrollbar orizzontale per mostrare il testo nascosto dal bordo destro.
Larghezza della tabulazione Un modo semplice per aumentare la quantità di testo visibile sullo schermo è impostare la larghezza di tabulazione a 3 o persino 2 caratteri, soprattutto se usate loop e strutture indentate di tre o quattro livelli.
Contrassegnare i punti di interesse nel codice Non c'è nulla di più penoso che vedere uno speaker alla ricerca affannosa dei pezzi di codice che intende mostrare al pubblico. Per rintracciare velocemente i punti di interesse basta marcarli nel codice con un commento speciale riconosciuto dalla finestra Task List. Ecco come fare. Per prima cosa, usare la pagina Task List della finestra Tools-Options di Visual Studio per definire un comment token personalizzato di nome SHOW e con priorità low. A questo punto è sufficiente marcare il codice con commenti opportuni, usando opzionalmente un numero dopo il commento per indicare l'ordine con cui i vari punti devono essere mostrati, ad es. // SHOW: 1. Il costruttore della classe A questo punto si possono visualizzare questi commenti speciali scegliendo il comando All dal sottomenu Show Tasks del menu contestuale della finestra Task List. Cliccando sull'intestazione della colonna Description si raggruppando tutti i commenti di tipo SHOW e li si ordina in base al numero progressivo. (Se ci sono più di 9 punti, usare numeri a due cifre, ad es. 01, 02, ecc.). Se si clicca sulla intestazione della colonne File, i commenti ritornano ad essere ordinati per posizione.
Per ritrovare velocemente punti nel codice che non sono segnalati da commenti, potete anche usare dei bookmark. Questi bookmark possono apparire nella finestra Task List se usate il comando Add Task List bookmark dal sottomenu Bookmarks del menu Edit, corrispondente alla combinazione Ctrl+K, Ctrl+H.
Stile uniforme del codice Usare uno stile il più standard possibile per il codice usato nelle demo preparate in anticipo: rispettare le indentazioni, commentare ogni blocco di righe, usare nomi significativi per campi, proprietà, e metodi, e così via.
Aggiungere un file Readme.txt al progetto Tutti i progetti demo di una certa complessità dovrebbero essere accompagnate da un file di testo che contiene le istruzioni per il setup. Se questo file è aggiunto al progetto in questione sarà visualizzato nella finestra del Solution Explorer e quindi sarà più facilmente notato quando i partecipanti installeranno gli esempi sul proprio computer. Se non vi fidate della vostra memoria, stampate il contenuto di questo file e tenetelo accanto alla tastiera, per essere sicuri di non omettere alcun passo importante.
Controllate le demo alla risoluzione 1024x768 Ecco un errore fin troppo frequente: tutte le demo sono preparate per la risoluzione che usate durante lo sviluppo (spesso 1280x1024 o superiori) e poi l'interfaccia utente funziona male alla risoluzione usata durante la sessione, che non supera mai 1024x768. Quindi accertatevi che tutte le vostre demo funzionino a questa risoluzione. Se vi sembra un grande sacrificio, pensate che fino a non molti anni fa la maggior parte dei proiettori che si trovavano anche nei migliori centri congressi supportava al massimo 800x600.
Scorciatorie nel menu Tools Aggiungere al menu Tools i comandi per richiamare le utility che usate più frequentemente durante le demo, ad esempio • lanciare ILDASM per dissassemblare l'eseguibile corrente • lanciare GACUTIL per registrare l'assembly corrente nella GAC • aprire il Window Explorer nella cartella del progetto. (In VS2005 questo comando esiste già, basta fare click con il tasto destro sulla tab nella parte superiore dell'editor di codice.) • lanciare il prompt di Visual Studio .NET nella cartella contenente gli eseguibili, in modo da poter poi lanciare con facilità gli altri tool di .NET
Macro e toolbar custom per altre azioni comuni E' buona norma preparare delle macro per le azioni comuni che prendono più tempo, ad esempio per creare una proprietà con tanto di blocco get/set oppure per attivare e disattivare i numeri di riga. Queste macro si possono richiamare dal Macro Explorer o meglio ancora mediante una toolbar custom costruita per l'occasione. Una toolbar del genere può essere utile anche per richiamare alcuni comandi di Visual Studio che sono annidati in menù particolarmente profondi o che corrispondono a modifiche delle impostazioni della dialog Tools-Options. Se usate Visual Studio 2005, non dimenticate delle expansions.
Durante le demo
Operazioni di editing mediante mouse e menu di contesto Usate preferibilmente il mouse per invocare un comando invece della combinazione di tasti che corrisponde al comando. In questo modo gli spettatori possono rendersi conto di quello che sta avvenendo, senza dover tirare a indovinare quali tasti state premendo. Questo suggerimento vale anche per i comuni comandi di editing come Copy, Cut, Paste, Delete, ecc. Se non usate il mouse, almeno dichiarate a voce quello che state facendo in ogni momento.
Evidenziare la posizione del mouse Attivare l'opzione "Show location of pointer when I press the CTRL key" che si trova nella pagina Pointer Options della dialog box con le proprietà del mouse (raggiungibile da Control Panel). In questo modo è possibile attirare l'attenzione degli spettatori sulla posizione del mouse semplicemente premendo il tasto Control.
Editor a pieno schermo Quando si analizza un pezzo di codice istruzione per istruzione, è opportuno usare la modalità full-screen dell'editor di Visual Studio .NET, attivabile e disattivabile con la combinazione Shift+Alt+Enter, in modo da massimizzare l'area a disposizione e ridurre la necessità di eseguire lo scrolling orizzontale per mostrare le righe troppo lunghe.
Evitare lo scrolling orizzontale Come indicato in precedenza, è opportuno che le istruzioni nelle demo non siano tanto lunghe da richiedere l'uso della scrollbar orizzontale per mostrare il testo nascosto. Un sistema alternativo consiste nell'attivare e disattivare velocemente il line wrapping delle righe con la combinazione di tasti Ctrl+R, Ctrl+R. (Oppure Ctrl+E, Ctrl+W in Visual Studio 2005.) Visual Studio viene anche fornito con le macro predefinite TurnOnWordWrap e TurnOffWordWrap che modificano questa impostazione per tutti i linguaggi supportati.
Outlining del codice Utilizzare le capacità di outlining di Visual Studio per collassare ed espandere le single classi e i singoli metodi, in modo da poter attirare l'attenzione degli spettatori sulle porzioni di codici realmente importanti. E' anche opportuno usare la direttiva #region per creare porzioni di codice che possono essere facilmente collassate, ad esempio l'insieme dei metodi che implementano una interfaccia.
Numeri di riga Se accettate che gli spettatori possano fare delle domande sul codice che state mostrando, attivate la visualizzazione dei numeri di riga in modo da metterli in grado di indicare velocemente a quale porzione del codice si riferiscono. Visto che questa opzione si attiva dalla dialog Tools-Options, conviene creare una macro e assegnarvi una shortcut. Visual Studio viene fornito con le macro TurnOnLineNumbers e TurnOffLineNumbers che attivano e disattivano questa feature per tutti i linguaggi supportati.
Confrontare due porzioni di codice Se occorre mostrare due porzioni di codice allo stesso tempo, ad esempio per permettere di apprezzare piccole differenze, si dovrebbe dividere a metà la finestra dell'editor. Ci sono due modi di farlo, a seconda che il codice si trova nello stesso file sorgente oppure in due file differenti. Nel primo caso, si divide in due la finestra dell'editor trascinando verso il basso il piccolo rettangolino grigio che si trova immediatamente sopra la scrollbar verticale. Nel secondo caso è invece necessario creare un nuovo Tab Group orizzontale (cliccare con il tasto destro su una delle tab mostrate nella parte alta della finestra dell'editor) e accertarsi che i due file in questione appartengono a due gruppi distinti (se non lo sono, basta eseguire il drag-and-drop di una linguetta su un altro gruppo).
Navigazione veloce nel codice Usate tutti i mezzi e i comandi che Visual Studio mette a disposizione per muoversi velocemente nel codice. Eccone alcuni, non tutti noti come meriterebbero: • Evidenziare il nome di una variabile, metodo, o classe e premere F12 per saltare alla definizione della classe • navigare direttamente alla definizione di una classe o metodo mediante l'Object Browser o il Class Viewer • premere il tasto Ctrl+- (meno) per tornare alla posizione precedente (questa la sanno in pochi!!! ) • creare uno o più bookmark per poi rintracciarli velocemente mediante la finestra Bookmarks. • usare il comando Find per cercare velocemente tutte le occorrenze delle variabili, invocazioni a metodi, ecc.
Porzioni di codice pre-confezionate Scrivere codice "al volo" durante la sessione è molto efficace e dà agli spettatori l'impressione che lo speaker padroneggia davvero la materia, ma se si tratta di scrivere più di 4-5 righe di codice molti tendono a distrarsi e a confondersi, anche perché di solito scrivendo codice in questo modo non si aggiungono i commenti necessari. All'altro lato dello spettro vi sono le applicazioni demo preparate in anticipo e complete e funzionanti, che però di solito non mettono in evidenza il ragionamento che ha seguito lo sviluppatore per arrivare al risultato finale. Ecco alcune soluzioni "intermedie": • Scrivete in precedenza il codice nel programma ma commentatelo, in modo da poterlo poi "scommentare" velocemente con Ctrl+K, Ctrl+U. • Scrivete in precedenza il codice nel programma, ma usate una direttiva #if false per non farlo eseguire; se invece della costante false usate una variabile di compilazione, questo meccanismo permette di attivare o nascondere più pezzi di codice con una modifica in un unico punto del codice (oppure nelle proprietà di progetto). • Per le porzioni di codice di una certa dimensione, preparate un file di testo contenenti le varie porzioni di codice, caricatelo in Notepad, e durante la sessione usate il copia-e-incolla per inserire tali pezzi di codice in determinati punti del listato. • Come sopra, ma prima della sessione copiate i pezzi di codice sulla Toolbox di VS come frammenti di testo, da dove potete riprenderli mediante un semplice drag-and-drop • Usate un qualsiasi code librarian per conservare i frammenti di codice che vi interessano, ad esempio la versione freeware di CodeBox (www.dotnet2themax.com/codebox). • Se la sessione verte su Visual Studio 2005, potete preparare delle porzioni di codice e inserirle con il comando Insert Snippet.
L'utility Magnifier Se volete attirare l'attenzione su alcuni particoli della interfaccia utente del vostro programma (o di Visual Studio, o di un altro programma qualsiasi), usate l'utility Magnifier (che trovate nel menu Accessibility del menu Accessories di Windows). Su Internet trovate una marea di utility simili e anche più potenti.
ATTENZIONE AL TEMPO CHE PASSA !!! L'ultimo consiglio è in realtà il più importante: ricordatevi di indossare l'orologio e soprattutto di guardarlo in continuazione. Non c'è nulla di peggio di vedere uno speaker che si affanna per finire le sue slide in tempo, perchè ha indugiato troppo all'inizio o ha accettato troppe domande dal pubblico. Se il vostro orologio ha un allarme, impostatelo a 15 minuti prima della fine della sessione. Se avete un palmare, usate l'allarme del palmare. Se non avete un palmare, portatevi una sveglia sul palco, oppure usate una qualsiasi utility sul computer che emetta un beep.
Se non trovate una di queste utility su Internet o non sapete scriverne una, mi chiedo che ci fate su un palco di una conferenza per programmatori Ma anche in quel caso, almeno chiedete a un amico in prima file di tossire violentemente quando si accorge che state per "sforare" ....
Sono sicuro che molti di voi hanno qualcosa da aggiungere a questo elenco, sia perchè hanno avuto modo di parlare in pubblico sia perchè hanno visto altri speaker NON fare qualcosa che avrebbero dovuto fare (o fare qualcosa che NON avrebbero dovuto fare, il che è lo stesso). Se ne avete voglia, lasciate pure un commento e aggiornerò l'elenco.
di Marco BellinasoO almeno questo è il titolo di questa pagina su MSDN In realtà per ora io ne ho contate 47 di applicazioni di esempio, ma forse ne ne sono perse 3 perchè in fondo alla pagina c'è scritto "Coming soon - The remaining 51 samples are coming soon. Stay tuned." 
Ma non andiamo a pignolare, anche quello che c'è già è decisamente benvenuto! Le applicazioni sono fornite in C# o VB.NET e sono divise nelle seguenti categorie:
- Base Class Libraries: come cambiare le ACL di un file, implementare animazioni su console, scaricare file da FTP, comprimere e decomprimere file, usare le generic collections, ricavare informazioni sui drive, usare la classe Stopwatch, eseguire il PING e qualche altra operazione di networking.
- Data Access: query asincrone, uso e confronto di Datareader con DataSet, update batch, paginazione, bulk update, salvataggio e recupero di immagini dal DB, classi factory, uso di MARS, Notification Services, e UDT di SQL Server 2005.
- Web Development: master pages, API e controlli di membership, profili, controlli menu e TreeView, web part, data binding con i vari componenti xxxDataSource.
- Windows Forms: task asincroni, componenti BindingNavigator e BindingSource, estensioni alla DataGridView standard, i nuovi controlli MaskedTextBox, WebBrowser, StatusStrip, ToolStrip, SplitContainer e LayoutPanel.
Insomma, se ancora non avete dato un'occhiata a .NET 2.0 e VS.NET 2005, questi esempi pronti per essere eseguiti sono un'ottima occasione per vedere velocemente alcune delle novità introdotte. Complimenti per l'iniziativa, e come dice la pagina stessa: tenete d'occhio la pagina per gli ulteriori 51 (o 54?) esempi che hanno già promesso.
|
|
Feed di Blog2theMax
Cerca nel blog
Archivio
| | Sun | Mon | Tue | Wed | Thu | Fri | Sat | | 28 | 1 | 2 | 3 | 4 | 5 | 6 | | 7 | 8 | 9 | 10 | 11 | 12 | 13 | | 14 | 15 | 16 | 17 | 18 | 19 | 20 | | 21 | 22 | 23 | 24 | 25 | 26 | 27 | | 28 | 29 | 30 | 31 | 1 | 2 | 3 | | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
Categorie
Powered by: newtelligence dasBlog 1.7.5016.2
|