Inside Microsoft® Visual Studio® .NET 2003 [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Inside Microsoft® Visual Studio® .NET 2003 [Electronic resources] - نسخه متنی

Brian Johnson

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید










Creating Wizard Templates


A wizard's purpose is to create a new project or add code files to an existing project. But where does the code for these projects or project items come from? The answer is template files. Templates are the source code files that a wizard adds to a solution or an existing project. These files are placed on disk, and when a wizard wants to add the project or file, the template project and the files the project references or the file for an Add New Item wizard is copied into a folder the user specifies and is then added to the solution or project.

Templates are normally created using one of the wizards for generating a project or a project item, and then the file(s) of the new project are modified to fit the requirements of the project or project item you're trying to create. The code that's created and added to a solution when you run the Add-in Wizard is generated in this way. We used the C# and Visual Basic Class Library Wizard to generate the base project and then modified this project to implement the add-in. The Add-in Wizard locates this project and adds it to the solution, and then the files in this newly created project are modified to conform to the options the user selected when running the wizard.


Using Template Files


Once you've created the template files, you need a way to add them to the solution or project. Visual Studio .NET supports a number of methods to accomplish this. In Chapter 8, we explored the project model but purposely left out a discussion of two methods of the Solution object: AddFromFile and AddFromTemplate. These two methods are used to add project templates to a solution. AddFromFile adds a reference in the solution file to the project, keeping the project file where it exists on disk. Calling this method is analogous to right-clicking on the solution node in the Solution Explorer window, choosing Add | Add Existing Project, and browsing to a project file. Wizards, however, usually want to add a copy of a project template to the solution; otherwise, the user of the generated project would modify the template project and subsequent running of the wizard would add a reference to this same modified project. Wizards should normally use the AddFromTemplate method, which copies the project template and its associated files to a destination folder and then adds a reference of this copy to the solution. The signature for AddFromTemplate is


public EnvDTE.Project AddFromTemplate(string FileName, string Destination,
string ProjectName, bool Exclusive = false)

Here are the arguments:


FileName

The full path to the project template.


Destination

The location on disk to which the project and the files it references are copied. The wizard should create this destination path before AddFromTemplate is called.


ProjectName

The name assigned to the project file and the name in Solution Explorer where it has been copied. Don't attach the extension of the project type to this argument.


Exclusive

If this parameter is set to true, the current solution is closed and a new one created before the template project is added. If this parameter is false, the solution isn't closed and the newly created project is added to the currently open solution.


Note

If the Exclusive parameter is set to true when AddFromFile or AddFromTemplate is called, the existing project is closed without the user being given the option to save any modified files. You should give the user the option to save by calling the ItemOperations.PromptToSave property before calling AddFromTemplate or AddFromFile.

AddFromTemplate and AddFromFile will add a template project from anywhere on disk; that is, the files don't need to be stored in a specific locationjust a place that is convenient to find. A common place to store the template files is in a folder named Templates that has been placed in the same folder as the COM object implementing the wizard. If the wizard is built using a language supported by the .NET Framework, you can use reflection to calculate the path to the templates using code like this:


string templatePath =
System.Reflection.Assembly.GetExecutingAssembly().Location;
templatePath = System.IO.Path.GetDirectoryName(templatePath) +
"\\Templates\\";

The AddFromTemplate method adds a project template to a solution, but the ProjectItems collection has a series of methods for adding files to an existing project: AddFromDirectory, AddFromFileCopy, AddFromFile, and AddFrom­Template. AddFromDirectory accepts as a parameter the path to a folder on disk; this folder is searched recursively, causing all its contained files and subfolders to be added to the project. AddFromFileCopy and AddFromFile both perform the same basic operation, adding a reference to the specified file on disk to the project. However, AddFromFileCopy copies the file into the project's directory structure before adding this reference. AddFromFileCopy differs from the AddFromTemplate method of the ProjectItems collection (not to be confused with the AddFromTemplate method of the Solution object) in that AddFrom­Template copies the file into the folder on disk for the project and then the project might make some modifications to the file after the files are added.

Here are the signatures and parameters for these methods:


public EnvDTE.ProjectItem AddFromDirectory(string Directory)
public EnvDTE.ProjectItem AddFromFileCopy(string FilePath)
public EnvDTE.ProjectItem AddFromFile(string FileName)
public EnvDTE.ProjectItem AddFromTemplate(string FileName, string Name)


Directory

The source folder on disk. Searches for files and subfolders begin with this folder.


FilePath / FileName

The location of the file to copy or add a reference to.


Name

The resulting name of the file. This name should have the extension of the file type.


Each of these methods returns a ProjectItem, an object that can be used to perform operations on the file that was added (such as opening the file or accessing the file's contents).


Solution Filenames and the New Project Wizard


When a New Project wizard is run, a solution filename might or might not be specified within the ContextParams array, depending on whether the user has selected the Create Directory For Solution check box, which is visible after the user clicks More in the New Project dialog box. If the check box is selected, the New Solution Name box is enabled, allowing the user to specify a new directory name for the solution. If the user doesn't select the check box, when a project is created using Solution.AddFromTemplate you should use the name specified for the project in the ContextParams array as the name of the project, the name of the solution file (if the exclusive argument in the ContextParams array is true and a solution is not currently open), and the name of the folder on disk to contain those files. These solution and project files should also be stored in the same folder. If the user selects the check box, the solution name argument in the list of context parameters is valid and you should name the root directory for the solution and the solution file using the solution name argument.

To create and name a solution file, you can use the Solution.Create method (as discussed in Chapter 8) by passing in the path for where to store the solution file and the name of the solution as arguments. Under the directory for the solution file, you should create a new folder to contain the project file, and you should name both the folder and the project with the project name passed into the ContextParams array.


Replacements


When you use a template to create a new project or a new file, the code that's generated will most likely not match the requirements for your wizard. For example, if the C# Class Library Wizard is run, the class that is generated is named Class1. The user can modify this class manually to give it a different name, but it's better to dynamically give the class a name that reflects the kind of class the wizard is generating (such as the name Wizard if the class implements a wizard). You can do this by replacing specific textual tokens within the template files after they've been added to the solution or project. To make a replacement, you use the editor object model to search for the token, and then you modify the token's text. Tokens can be just about any text that is placed in the file, but normally they have a specific format that is distinguished from other text within the file. A common token used as a placeholder for the class name is %CLASSNAME%. The template for the class with the tokens added would look something like this:


public class %CLASSNAME%
{
public %CLASSNAME%()
{
//
// TODO: Add constructor logic here
//
}
}

The following macro, named MakeReplacements, replaces tokens in a file. Some of the concepts that this macro uses, such as the EnvDTE.TextPoint objects, might be unfamiliar to you, but we'll cover them in Chapter 11.


Sub MakeReplacements(ByVal projectItem As EnvDTE.ProjectItem, _
ByVal token As String, _
ByVal replaceWith As String)
Dim window As EnvDTE.Window
Dim textDocument As EnvDTE.TextDocument
Dim textRanges As EnvDTE.TextRanges
Dim findOptions As Integer
findOptions = EnvDTE.vsFindOptions.vsFindOptionsFromStart + _
EnvDTE.vsFindOptions.vsFindOptionsMatchCase + _
EnvDTE.vsFindOptions.vsFindOptionsMatchWholeWord
'Open the specified project item.
' This will open the file but show it hidden:
window = projectItem.Open(EnvDTE.Constants.vsViewKindTextView)
'Find the TextDocument object for the project item:
textDocument = window.Document.Object("TextDocument")
'Replace all the text that matches token with the replaceWith text:
textDocument.ReplacePattern(token, replaceWith, _
findOptions, textRanges)
End Sub

Once you've opened the file that contains the class definition and made it the active document (by using the ProjectItem object returned by the Add* methods of the ProjectItems collection), you can call the following macro to replace the %CLASSNAME% token with the class name MyClass:


Sub MakeReplacements()
MakeReplacements(DTE.ActiveWindow.ProjectItem, _
"%CLASSNAME%", "MyClass")
End Sub

Among the many variations on searching for tokens and replacing the text is deleting the text between two separate tokens. This technique is useful if the user selects an option in the user interface of a wizard that would cause a bit of code not to be needed. The Add-in Wizard uses this technique to remove the code for creating a command bar button when the Yes, Create A 'Tools' Menu Item check box on the Choose Add-in Options page of the Add-in Wizard has been cleared. The following macro deletes the text between two tokens:


Sub DeleteBetweenTokens(ByVal projectItem As EnvDTE.ProjectItem, _
ByVal token1 As String, _
ByVal token2 As String)
Dim window As EnvDTE.Window
Dim textDocument As EnvDTE.TextDocument
Dim tokenEndPoint As EditPoint
Dim tokenStartPoint As EditPoint
Dim findOptions As Integer
findOptions = EnvDTE.vsFindOptions.vsFindOptionsMatchCase + _
EnvDTE.vsFindOptions.vsFindOptionsMatchWholeWord
'Open the specified project item.
' This will open the file, but show it hidden:
window = projectItem.Open(EnvDTE.Constants.vsViewKindTextView)
'Find the TextDocument object for the project item:
textDocument = window.Document.Object("TextDocument")
'Create edit points for searching:
tokenEndPoint = textDocument.StartPoint.CreateEditPoint()
tokenStartPoint = textDocument.StartPoint.CreateEditPoint()
'Loop while all start / end tokens can be found:
While (tokenStartPoint.FindPattern(token1, findOptions))
If (tokenEndPoint.FindPattern(token2, findOptions, tokenEndPoint)) _
Then
'Move the selection to bracket the start / end tokens:
textDocument.Selection.MoveToPoint(tokenStartPoint, False)
textDocument.Selection.MoveToPoint(tokenEndPoint, True)
'Delete the selection:
textDocument.Selection.Delete()
Else
Exit While
End If
End While
End Sub

If our template code were modified to look like this


public class %CLASSNAME%
{
public %CLASSNAME%()
{
//
// TODO: Add constructor logic here
//
}
%BEGINOPTIONALCODE%
void SomeOptionalCode()
{
}
%ENDOPTIONALCODE%
}

after running this macro


Sub MakeReplacements2()
MakeReplacements(DTE.ActiveWindow.ProjectItem, _
"%CLASSNAME%", "MyClass")
DeleteBetweenTokens(DTE.ActiveWindow.ProjectItem, _
"%BEGINOPTIONALCODE%", "%ENDOPTIONALCODE%")
End Sub

the following code would result:


public class MyClass
{
public MyClass()
{
//
// TODO: Add constructor logic here
//
}
}


Raw Add New Item Templates


An Add New Item wizard is generally used to add a file to a project and then modify the file by making replacements to it. However, sometimes a template file doesn't need to be modified after it's been inserted into a project. An example of this is a text file. When the user chooses to add a text file to a project, a blank file is added. Creating a wizard object just to insert a blank file is a waste of both disk space (to hold the wizard DLL) and time. To get around this, Visual Studio .NET allows what are called raw templates. When displaying the Add New Item dialog box, Visual Studio .NET not only searches for and shows .vsz files in the right panel of that dialog box but it also shows any other files within the folder where .vsz files can be placed. If the user selects one of these raw template files in the Add New Item dialog box, the equivalent of an AddFromFileCopy is performed on the filethe file is copied into the directory structure for the project that the item is being added to, and then the file is added to the project. To create a raw template, you simply create a file and place that file into the path returned by calling the ProjectItemsTemplatePath method and specifying the appropriate project type.


/ 118