Modifica dei template di Visual Studio 2005
a cura di Sabrina Cosolo & Rudy Azzan (requisiti: conoscenza generica di Visual Studio)Premessa
Dato che il mio collega Rudy ha una notevole capacità nel rintracciare plugin e snapin che permettano di lavorare meglio e più in fretta con Visual Studio 2005, e visto che ha modificato tutti i nostri template standard per le classi in modo tale che troviamo già le strutture predisposte secondo le regole che ci siamo dati internamente, sia per quel che riguarda lo stile, che per i commenti e le funzionalità standard delle stesse, gli ho chiesto di prepararmi degli appunti per capire come funzionano i template di Visual Studio, in modo da poter scrivere un breve articolo e dare una mano a tutta la community. Dal suo riassunto essenziale, durante le mie ferie, mi sono presa un pomeriggio per elaborare un po' di screenshot e scrivere qualcosa di meno stringato e adatto anche a chi lavora con Visual Studio da un po', ma non ha ancora avuto il tempo per "sbudellarlo" :o) per bene.In questo articolo spiegheremo come accedere ai template di default per Progetti e Item di Visual Studio .NET 2005 e come modificare ed aggiornare uno di essi per adattarlo alle nostre esigenze. Poi ci spingeremo un po' più in là e proveremo a crearne uno per tipo completamente nuovo e personalizzato.
Prima di iniziare
dobbiamo individuare le cartelle dove trovarli:
Come possiamo vedere dall'immagine, i template si trovano nella cartella di installazione di Visual Studio, più precisamente sotto
%ProgramFiles%\Microsoft Visual Studio 8\Common7\IDE\
dove %ProgramFiles% è la cartella programmi e può essere ad esempio c:\programmi oppure c:\program files, in base al sistema operativo e alla lingua in cui è installato.Sotto questo percorso, troviamo:
ProjectTemplates, per i template relativi ai progetti
ItemTemplates, per i template relativi agli oggetti da inserire in un progetto
SolutionTemplates, per i template relativi alle soluzioni.
All'interno delle cartelle principali possiamo osservare ulteriori suddivisioni, per prima cosa una cartella per ogni linguaggio (salvo per le soluzioni che sono neutre).
Per i Progetti, vi è una serie di cartelle che li suddividono per argomento, ad esempio Database, SmartDevice, Windows;
All'interno delle cartelle di livello più basso per ogni linguaggio, troveremo una ulteriore sottocartella che si chiama 1033 sul mio pc, ed è collegata alla lingua di installazione di Visual Studio, nel mio caso l'Inglese (1040 per l'italiano). Aprendo questa cartella, troveremo una serie di files .ZIP; ciascuno di essi è un template di Soluzione, Progetto oppure Item.
Individuate le "vittime" vediamo un po' come "operare" un template a cuore aperto...
Modificare un Template esistente
Per aprire un template, non facciamo altro che estrarre il contenuto dello .zip in una cartella di lavoro a noi gradita es: c:\temp, nel nostro esempio, abbiamo aperto ClassLibrary.zip dalla cartella Windows, e apriamo il file class1.vb o class1.cs in base alle nostre preferenze. Qui sotto vediamo i due templates:
VB Public Class $itemname$ End Class C#using System; using System.Collections.Generic; using System.Text; namespace $safeprojectname$ { public class Class1 { public Class1() { } } }Potremmo definire desolante il template di VB e poco meno quello di C#, pertanto vediamo di metterci dentro alcune cose che possono tornarci utili nella generazione e gestione di una classe:
VB#Region "Imports Directives" Imports System Imports System.Text Imports System.Collections.Generic #End Region Public Class $safeitemrootname$ #Region "Variabili private" ''' <summary> ''' Variabile contenente il nome della classe per la gestione eccez ''' </summary> ''' <remarks></remarks> Dim mClassName As String = _ System.Reflection.MethodBase.GetCurrentMethod().ReflectedType.Name #End Region #Region "Eventi Pubblici" 'TODO: Inserire qui gli eventi della classe #End Region #Region "Costruttore" ''' <summary ''' Costrutore ''' </summary ''' <remarks></remarks Public Sub New() 'TODO:Inserire qui il codice di 'inizializzazione dei membri della classe End Sub #End Region #Region "Proprieta'" 'TODO: Inserire le property della classe #End Region #Region "Metodi Privati" 'TODO: Inserire qui i metodi privati della classe #End Region #Region "Metodi Pubblici" 'TODO: Inserire qui i metodi pubblici della classe #End Region End Class C##region Using directives using System; using System.Collections.Generic; using System.Text; #endregion namespace $safeprojectname$ { ///<summary> /// Descrizione della classe: ///</summary> ///<remarks> ///</remarks> public class $safeitemrootname$ { #region Variabili private ///<summary> /// Nome della classe usato per debug nella generazione delle eccez ///</summary> ///<remarks> ///</remarks> private readonly string mClassName = System.Reflection.MethodBase.GetCurrentMethod().ReflectedType.Name; #endregion #region Eventi //TODO: Inserire qui gli eventuali eventi pubblici della classe #endregion #region Proprietà' //TODO: Indicare qui le Proprietà della classe #endregion #region Costruttore ///<summary> /// Costruttore ///</summary> ///<remarks> /// V.1.0 ///</remarks> public $safeitemrootname$() { //TODO: Inserire il codice per //l'inizializzazione dei membri della classe } #endregion #region Metodi privati //TODO: Inserire qui i metodi privati della classe #endregion #region Metodi pubblici //TODO: Inserire qui i metodi pubblici della classe #endregion } }In questo caso, oltre ad aggiungere il costruttore anche in VB, ho inserito una serie di Region, ove raggruppare in modo logico il contenuto di una tipica classe; inoltre, ho inserito la variabile mClassName, che troverete in tutti gli esempi dei miei articoli, in quanto viene utilizzata per la gestione delle eccezioni, indicando al chiamante la classe ove una eccezione ha avuto origine. Presto diventerà, per voi, la 'famigerata' mClassName.
Come sempre, specifico che questo è solo un esempio: ciascuno può creare il proprio template come preferisce.
Una volta modificato il codice esempio, andiamo a vedere in cosa differisce dal normale codice di una classe: se avete guardato bene, vi sarete accorti che ci sono una serie di parole nella forma $definizione$, queste parole chiave sono dei placeholder (segnaposto) per la sostituzione di valori all'interno del template.
La più semplice e usata in ogni template, o quasi, è $safeitemrootname$, che prende il nome dato dall'utente al nuovo item; ce ne sono due versioni, come vedremo nell'elenco seguente, $itemname$ e quella con il prefisso safe; la differenza fra le due è che, se qualche pazzoide desse ad una classe un nome con spazi, caratteri strani o altre cose non permesse, nella versione safe queste pazzie vengono rimosse. Ma ovviamente quasi tutti sanno (vero?) che è una cosa utile ad evitare acidità di stomaco dare, al file che contiene una classe, lo stesso nome della stessa, e, ove non sia strettamente indispensabile il contrario, mettere una sola classe per ogni file (quando non dividerla in più files).
Vediamo una tabella con la lista dei placeholder ed il loro significato e vi ricordiamo che non tutti i placeholder funzionano in tutti i template, non tutti i placeholder possono essere messi in tutti i files. Oltre ai files delle classi base, in un template ci sono una serie di altri oggetti che possono essere personalizzati, ma, in questo caso, vi invitiamo a creare un template vostro e nuovo, piuttosto che modificarne uno esistente. Faremo un esempio di come si fa più avanti in questo articolo.
Nome parametro Descrizione $itemname$ Nome che avete fornito quando avete inserito un nuovo item $projectname$ Nome che avete dato al vostro progetto $registeredorganization$ Nome della vostra organizzazione che avete inserito quando avete installato windows. Lo trovate nel registry in:
HKLM\Software\Microsoft\WindowsNT\CurrentVersion\RegisteredOrganization$year$ Anno corrente $guidx$ x da 1 a 10 Da uno a dieci identificativi univoci.
Il guid 1, di solito, è per l'ID della typelibrary, se il progetto è esposto come COM compatibile$clrversion$ Versione del common language runtime installato $machinename$ Nome del computer in uso $rootnamespace$ Il root namespace del progetto corrente $safeitemname$ Nome che avete fornito quando avete inserito un nuovo item con tutti i caratteri unsafe e gli spazi rimossi $safeprojectname$ Nome che avete dato al vostro progetto con tutti i caratteri unsafe e gli spazi rimossi $time$ Data e ora corrente nel formato “DD/MM/YYYY 00:00:00” $userdomain$ Il dominio dell’utente corrente $username$ Nome dell’utente corrente La sostituzione dei placeholder all'interno dei files del progetto deve essere pilotata in modo corretto. Quando creeremo i nostri template nuovi, sarà Visual Studio a preoccuparsene, però, se vogliamo sapere qualcosa di più su come funziona tutto questo, possiamo dare un'occhiata al file .vstemplate che troviamo all'interno dello .zip che stiamo modificando.
(qualche riga, in questo come in altri listati, è mandata a capo per ragioni di visibilità [n.d.r.])<VSTemplate Version="2.0.0" Type="Project" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005"> <TemplateData> <Name Package="{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}" ID="2322" /> <Description Package="{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}" ID="2323" /> <Icon Package="{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}" ID="4547" /> <ProjectType>CSharp</ProjectType> <SortOrder>20</SortOrder> <NumberOfParentCategoriesToRollUp>1</NumberOfParentCategoriesToRollUp> <CreateNewFolder>true</CreateNewFolder> <DefaultName>ClassLibrary</DefaultName> <ProvideDefaultName>true</ProvideDefaultName> </TemplateData> <TemplateContent> <Project File="ClassLibrary.csproj" ReplaceParameters="true"> <ProjectItem ReplaceParameters="true" TargetFileName="Properties\AssemblyInfo.cs"> AssemblyInfo.cs</ProjectItem> <ProjectItem ReplaceParameters="true" OpenInEditor="true">Class1.cs</ProjectItem> </Project> </TemplateContent> </VSTemplate>Quello che ci interessa sono le righe comprese tra i tag ProjectItem (all'interno di Project all'interno di TemplateContent: queste righe indicano i files in cui è necessario sostituire i placeholders di configurazione e l'attributo ReplaceParameters="true" indica che la sostituzione è attiva per questo file.
Se osserviamo il tag Project, possiamo vedere come lo stesso attributo ReplaceParameters="true" è stato inserito anche a livello di progetto, per fare in modo che i parametri siano sostituiti nei file di progetto, in cui non abbiamo ancora curiosato.
Una cosa interessante, sempre a proposito di placeholder e quindi di parametri sostituibili, è il fatto che possiamo inserire all'interno del template uno o più parametri personalizzati da noi, che possono essere posti all'interno del progetto oppure delle classi e sostituiti esattamente come i parametri standard che abbiamo indicato nella tabella più in alto.
<VSTemplate Version="2.0.0" Type="Project" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005"> <TemplateData> <Name Package="{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}" ID="2322" /> <Description Package="{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}" ID="2323" /> <Icon Package="{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}" ID="4547" /> <ProjectType>CSharp</ProjectType> <SortOrder>20</SortOrder> <NumberOfParentCategoriesToRollUp>1</NumberOfParentCategoriesToRollUp> <CreateNewFolder>true</CreateNewFolder> <DefaultName>ClassLibrary</DefaultName> <ProvideDefaultName>true</ProvideDefaultName> <CustomParameters> <CustomParameter Name ="$NomePlaceHolder$" Value ="Parametro1" /> <CustomParameter Name ="$UnAltroPlaceHolder$" Value ="true" /> </CustomParameters> </TemplateData> <TemplateContent> <Project File="ClassLibrary.csproj" ReplaceParameters="true"> <ProjectItem ReplaceParameters="true" TargetFileName="Properties\AssemblyInfo.cs"> AssemblyInfo.cs</ProjectItem> <ProjectItem ReplaceParameters="true" OpenInEditor="true">Class1.cs</ProjectItem> </Project> </TemplateContent> </VSTemplate>Questi parametri configurabili (CustomParameters), non verranno però ulteriormente discussi, in quanto al momento non ho modo di sperimentare come utilizzarli, ma se lo scopro, prometto di fare un addendum sul mio Blog o, se sarà una cosa più interessante, di scrivere un nuovo breve articolo.
Per ora possiamo concludere che modificare un template standard può permetterci di introdurre degli standard per la scrittura dei progetti e per la scrittura del codice sia nelle abitudini personali (ad esempio introducendo commenti e metodologie per la stesura delle classi), sia in un team di programmatori, ove è opportuno che tutti seguano lo stesso stile di scrittura, in modo che il codice scritto da ciascuno possa essere mantenuto e sviluppato da altri dopo di loro.
Installazione
Vediamo ora come fare ad installare il template che abbiamo modificato. Per farlo, esiste una utilità messa a disposizione da Visual Studio.
Per prima cosa, aggiorniamo il file .zip con il file da noi modificato (class1.cs o class1.vb). Per far questo possiamo usare WinZip, WinRar, Powerarchiver o qualsiasi altra utility di compressione. E copiamo il file .zip sulla cartella apposita nell'albero delle cartelle di Visual Studio (nel nostro caso: %ProgramFiles%\Microsoft Visual Studio 8\Common7\IDE\ ProjectTemplates\CSharp\Windows\1033 oppure ...\VisualBasic\Windows\1033).
Fatto questo, andiamo sul menu Programmi, espandiamo Microsoft Visual Studio\Visual Studio Tools, e selezioniamo il Visual Studio command prompt.
Usiamo il comando cd (change directory) del command prompt per spostarci in %ProgramFiles%\Microsoft Visual Studio 8\Common7\IDE\ e, da qui, lanciamo il comando devenv /installvstemplates (nella figura, vedete che ho anche 'dimenticato' la sottocartella Common7, ma non fateci caso più di tanto...)
Il programma aggiorna tutti i template in uso con quelli da noi inseriti nei file .zip sulla cartella di Visual Studio, aggiungendo quelli che avessimo creato di nuovi e modificando quelli da noi aggiornati. Il comando richiede usualmente un paio di minuti per l'esecuzione e non dà alcun segnale mentre sta lavorando. Quando termina riapparirà il familiare command prompt.
Siccome tutti i template vengono sovrapposti e siccome un aggiornamento, service pack o reinstallazione di Visual Studio andranno a rigenerare i template di default, se li modificate, conservatene una copia in una cartella personale in modo da non perderli.
Generare un Nuovo Project Template Personalizzato
Per generare con Visual Studio un nuovo template personalizzato (per esempio una classe personalizzata oppure una form personalizzata) non dovremo fare tutto a mano, perché Visual Studio, intelligentemente, ci mette a disposizione degli strumenti che ci aiutano in questo intento.
Ricordo che l'articolo è stato scritto con l'uso di Visual Studio 2005 Professional Edition in Inglese, pertanto non siamo certi che tutte queste funzionalità siano presenti in tutte le sue versioni. Vi ricordiamo, comunque, di verificare di aver installato anche l'SDK di .NET, perché alcune funzionalità sono contenute in esso.La prima cosa che dobbiamo fare è controllare se sul menu File di Visual Studio .NET abbiamo un'opzione che si chiama Export Template... usualmente situata sotto alle opzioni di salvataggio files. Se l'opzione non ci fosse, apriamo senza indugi Tools > Customize e selezioniamo sulla lista a sinistra File, cercando poi su quella a destra Export Template..., e spostiamo l'opzione all'interno del menu File ove deve essere ospitata.
A questo punto creiamo un nuovo progetto Windows (VB o C# in base a quello che preferiamo provare) dove andremo a generare il nostro template personalizzato. Personalizziamo il nome del Form1 in FrmMain e trasformiamolo in una Form MDI aggiungendo un titolo ed un'icona personalizzata. La soluzione avrà questo aspetto:
VB C#Una volta ottenuto il template che preferiamo, aggiorniamo la form aggiungendo del codice, i commenti, quello che riteniamo necessario introdurre come standard nelle nostre applicazioni Windows. Fatto questo, selezioniamo il progetto e dal menu File apriamo l'opzione Export Template... Apparirà questa finestra:
Visto che esportiamo un modello di Progetto, lasciamo selezionato la prima opzione. Dalla casella combinata in basso, selezioniamo il progetto che vogliamo esportare fra quelli inseriti nella soluzione e premiamo Next.
Apparirà la seconda finestra del nostro Wizard. Per prima cosa, togliamo la spunta dall'opzione "Automatically import the template into Visual Studio"; è importante, soprattutto se stiamo preparando il template per l'uso all'interno di un Team e vogliamo che venga installato nella cartella dei template standard, anziché in quella dei template personali.
Diamo al template un nome (casella in alto a destra) ed una descrizione (la frase può contenere spazi) nella casella in centro. Una volta premuto Finish, si aprirà la finestra del File Explorer di Windows dove Visual Studio avrà esportato il nostro template.
A questo punto, potremo salvare lo zip assieme agli altri template che abbiamo personalizzato e poi lo copieremo nella cartella standard dei template di progetto, per poi seguire le stesse istruzioni usate per aggiornare un template esistente, per cui dalla console di Visual Studio lanciamo l'utility di aggiornamento dei template del programma. Il nuovo template apparirà nella lista dei template di progetto disponibili.
Quando riproveremo a generare un nuovo progetto di tipo Windows, troveremo il nostro modello di progetto:
E, come potete notare, possiamo anche assegnargli un'icona a noi gradita per renderlo immediatamente visibile. Se proviamo a selezionarlo come base per un nuovo progetto, come per magia ci sarà la nostra form MDI che si chiama FrmMain con il codice che abbiamo deciso di inserire al suo interno.
Generare un Nuovo ItemTemplate Personalizzato
Proviamo ora a generare un ItemTemplate, quelli che a mio avviso saranno a noi più utili, perché ci permetteranno di generare delle strutture di classi già complete in cui dover inserire solo il minimo numero di modifiche. Per farlo, generiamo un nuovo progetto Visual Basic oppure C Sharp in base alle nostre esigenze, e inseriamo in questo progetto una classe.
Nel mio progetto, ho creato una classe per generare delle Entità, ovvero classi destinate alla gestione di dati.
Ho predisposto un'interfaccia, anzi una serie di interfacce che una classe di questo genere deve implementare e ho costruito la mia classe con il necessario a soddisfare le richieste dell'interfaccia che implementa, oltre al necessario per rendere la classe serializzabile.
Fatto questo, ho ottenuto qualcosa di questo genere:
VB C#Genereremo un nuovo ItemTemplate per la classe Entity, visto che l'interfaccia verrà predisposta una sola volta. Per farlo, dal menu File selezioniamo Export Template... e sulla prima maschera del wizard andiamo a selezionare l'opzione per la generazione di un nuovo ItemTemplate.
Nella schermata successiva selezioniamo il file contenente la nostra classe Entity.cs o Entity.vb.
Continuiamo, selezionando i Namespace delle DLL che vogliamo siano inserite come References, se il progetto in cui aggiungiamo la nostra classe non li avesse già fra le dll referenziate.
Quindi, andiamo avanti e diamo un nome ed una descrizione al nostro nuovo template e ricordiamoci di togliere il check per l'aggiunta automatica del template a Visual Studio, visto che lo aggiungeremo in seguito con la funzionalità già usata in precedenza.
A questo punto, premendo Finish, si aprirà la finestra del File explorer con il template appena creato, che noi andremo a copiare nella cartella degli ItemTemplate di Visual Studio, per poi lanciare dalla console il comando già utilizzato in precedenza per l'aggiornamento dei template.
Ricordiamoci di chiudere Visual Studio prima di lanciare l'aggiornamento dei template. Una volta fatto l'aggiornamento, se riapriamo la nostra soluzione di test, e dal menu di progetto selezioniamo Add New Item..., troveremo che nella lista dei possibili Items è stato aggiunto il nostro EntityVb o EntityCs, che, se scelto, crea una classe simile a quella del nostro esempio, con il suo nuovo nome inserito in tutti i posti in cui è necessario.
Conclusione
Ovviamente, questo articolo (i sorgenti del progetto sono scaricabili dall'area download) serve solo a dare un'idea delle potenzialità che Visual Studio è in grado di offrire per la generazione di template parametrizzati; vi rimando alla documentazione di MSDN per saperne di più.Feedback
Per commenti, richieste di chiarimenti, correzioni, su quanto esposto in questo articolo, potete scrivere sul blog dell'autrice.