ONDotNet.com    
 Published on ONDotNet.com (http://www.ondotnet.com/)
 See this if you're having trouble printing code examples


Create Project Item Wizards

by Niel Bornstein, author of .NET and XML
03/22/2004

In a recent project, my team had to produce a platform that included a set of base classes that other developers could use to develop Windows forms in Visual Studio .NET 2003. As we worked on the base classes, it became clear that our developers would be able to crank out their forms a lot faster if we could also generate stubs and skeleton code for all of the methods they needed to override in their own classes.

It's not a unique problem, and in fact it's one that Microsoft has already solved for the most basic file types. Every time you right-click on a project in Visual Studio .NET and select Add New Item..., the IDE creates a file and, depending on the type of file, even inserts the class name and other standard formatting.

We needed to go a step further and gather some information from the developer, such as the names of other related classes, whether to include certain components on a generated form, and whether to inherit the new form from one base class or another. One way to gather this kind of information from the user is the wizard metaphor.

What are Wizards?

A wizard is a tool that guides you through a particular process. The first wizards were introduced as a feature of Microsoft Publisher in 1991. Since then, they have appeared throughout the Microsoft product line, but they have gotten perhaps their best use in Microsoft's operating systems, where they can be seen every time you set up networking, download photographs from a digital camera, or send a fax.

Related Reading

Mastering Visual Studio .NET
By Ian Griffiths, Jon Flanders, Chris Sells

As a tool included with an operating system or software package, a wizard can save an end user from a potentially frustrating experience. Software used to come with manuals, and the functionality provided by wizards would be explained in the step-by-step instructions user manuals used to provide. Those instructions were not adaptive, like some wizards, however, and required the user to go back and forth between the manual and the software product being used. By integrating the task being accomplished with the step-by-step instructions that allow the user to accomplish the task, and adding the ability to adapt the process to other conditions, wizards have been a great boon to software usability.

In development tools, however, wizards can have the effect of hiding complexity from developers. Some hard-nosed, old-school programmers -- and I'll have to admit that I am one of them -- would argue that hiding complexity can be counter-productive in software development. If a black -- or gray -- box does all of the work for you, you may never understand what is really being done behind the scenes. A developer who doesn't understand what his program is doing is arguably a poor developer.

On the other hand, developers come in different flavors, with varying skill levels, and wizards can be created in such a way that they hide the complexity of a process without obscuring the process' products. If all you need, for example, is a kind of cut-and-paste on steroids, a wizard can definitely save you time. Such was the case in my project, and so I entered into the dark and murky world of Visual Studio .NET wizards.

How Is It Done?

My first stop on the road to wizardry was the MSDN topic "Creating Add-Ins and Wizards." While there is plenty of information available there about the Visual Studio .NET automation model, you have to drill down a bit to get to the information on creating wizards. The page titled "Creating a Wizard" seems a likely place to start.

A little further reading indicates that you need to create a DLL and implement the IDTWizard interface. IDTWizard has a single method, Execute, which allows you to present the wizard interface to the user. Implementing the Execute method leaves the presentation details completely up to you.

This seems an inefficient use of time for someone who really just wants to throw a simple one- or two-page wizard up on the screen. Rather than reinvent the wheel, it's much easier way to copy an existing wizard and change it to match your needs. To that end, let's look at some wizards that get installed with Visual Studio .NET by default.

Shortcuts to Your First Wizard

Most of the time, when you select the Add New Item... command from a project's context menu, you are presented with a list of file types and given the opportunity to type a file (and class) name. Visual Studio .NET then happily creates a file of the correct type, seemingly generating skeleton code for the named class, stubbing out any properties and methods required by the parent class, and adds it to the project. The familiar dialog box is shown in Figure 1.


Figure 1. The Add New Item dialog box.

I say "seemingly," because the code is not all generated on the fly. Each of the item types listed in the Add New Item dialog box has a set of scripts and templates behind it, which contain the logic needed to create the new file. In some cases, such as when creating a new class, the script does nothing and the template only inserts the class declaration and stubs out the constructor. In other cases, such as when creating an inherited control, the template may do more.

A little snooping about in the Program Files\Microsoft Visual Studio .NET 2003 directories on your PC will turn up the VC# subdirectory, where all the C# wizards and add-ins live. There's a directory under that one that contains wizards, called VC#Wizards. To pick one more or less at random, let's look at CSharpClassWiz.

There are several components to any Visual Studio .NET wizard, as you can see in CSharpClassWiz. They are HTML files, images, scripts, and templates.

HTML

The Visual Studio .NET wizard user interface engine is actually a web browser, and the various wizard forms that guide you through a process are simply HTML pages. These HTML pages can be localized, so they are placed in a directory named after the language ID (1033 for US English). The main HTML file is named default.htm, although there can be others for additional pages or tabs in the wizard. In the case of CSharpAddClassWizard, there are BaseClass.htm and Inheritance.htm.

Images

Images in Visual Studio .NET wizards may be used to show a company logo, user interface elements, or blank images used as spacers. Any image format supported by Internet Explorer can be used. Although images may also be localized, CSharpClassWiz does not use localized images.

Scripts

A Visual Studio .NET wizard may use JScript files to generate user interface elements, or to process input data to generate template files. Script files may be localized the same way as HTML files.

Templates

The files generated by the wizard typically start with a template that has placeholders for variables gathered from the user. Templates may be localized the same way as HTML and script files. The Templates directory also includes a file named Templates.inf, whose content is the name of the actual template file to copy.

In addition to the files in the specified directories, wizards may also make use of components in other directories. For example, CSharpAddClassWizard includes Script.js and Common.js from a completely different location, outside of the wizard's own directory. These script files contain functions used throughout the built-in wizards.

Related Reading

.NET & XML
By Niel Bornstein

In addition to the wizard components, there are files that have to be created or edited in order to inform Visual Studio .NET of the availability of a particular wizard.

The .vsz File

The .vsz file lives in the VC#\CSharpProjectItems directory, and contains information about how the wizard engine will present the wizard. For more information about the .vsz file, see the Microsoft Help topic.

LocalProjectItems.vsdir

This file, located in the VC#\CSharpProjectItems\LocalProjectItems directory, contains settings for how the Add New Item dialog box will present the new project item. These setting include the icon, its caption, where the template file is located, the default name of the new file, and other settings. Each wizard has a line with the following fields, delimited by pipes:

  1. Relative path to the .vsz file.
  2. GUID of a product containing resources.
  3. Name of the wizard to display in Add New Item dialog box, or resource ID (when prefixed with #) of the string containing the name.
  4. Sort order of the item.
  5. Long description of the wizard, also displayed in the dialog box, or resource ID.
  6. GUID of a product containing icons.
  7. Resource ID of the icon to display in the dialog box.
  8. Flags describing the wizard's behavior.
  9. Name of the template file, initially shown in the dialog box.
For more information on the .vsdir file, see the Microsoft Help topic.

Having pretty much figured out what makes the standard wizards tick, let's start creating our own.

Making It Work

First, the (very simple) requirements. The new wizard will be used to create a C# class that is a subclass of a specific class. The generated class will also depend on two other classes, a data table, and a strongly typed dataset, the names of which we'll collect from the developer. The developer should be able to select the namespace for the class as well as the namespace for the dataset, and make a choice between two difference base classes for the generated class. No other options should be presented to the developer. In the generated code, we'll provide stubs for a few abstract methods that must be overridden, and declare some properties whose return types are the types whose names we collected from the developer.

Those simple requirements out of the way, it's fairly easy to see what needs to be done. Here are the steps to be taken to create the new wizard, CSharpAddCMSimpleBusinessClassWizard:

  1. Copy the CSharpClassWiz directory to CSharpAddCMSimpleBusinessClassWizard.
  2. Create a file called CSharpAddCMSimpleBusinessClassWizard.vsz in VC#\CSharpProjectItems and make its contents the following:
    VSWIZARD 7.0
    Wizard=VsWizard.VsWizardEngine.7.1
    Param="WIZARD_NAME = CSharpAddCMSimpleBusinessClassWizard"
    Param="WIZARD_UI = FALSE"
    Param="PROJECT_TYPE = CSPROJ"
  3. Edit the default.htm file and delete the unneeded Bases.htm and Interfaces.htm files. We'll also make some changes to default.htm.
  4. Delete the template file NewCSharpFile.cs and create a new one called SimpleBusinessClass.cs.
  5. Add the following line to the LocalProjectItems.vsdir file, telling Visual Studio where to find CSharpAddCMSimpleBusinessClassWizard and its support files and resources. Note that I've borrowed the icon from the add class wizard, and used inline text in the file rather than pointing to a resource for other strings.
    ..\CSharpAddCMSimpleBusinessClassWizard.vsz|
    	{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}|
    	New Simple Business Class|
    	2|
    	Add a new simple business class|
    	{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}|
    	4515|
    	0|
    	SimpleBusinessClass.cs

    We added line breaks to make it easier to show.

Restart Visual Studio .NET 2003, and the next time you right-click on a project and select Add New Item..., you'll see the icon labeled "New Simple Business Class." Click on it, and you'll see the wizard we designed (Figure 2).


Figure 2. Your New Wizard

Conclusion

I've shown you one way to add a New Item wizard to Visual Studio .NET 2003 with a minimum of fuss and precious little code. I hope you find this technique useful as you continue the permanent quest for greater productivity.

Niel Bornstein is a Senior Architect for Novell's Systems and Resource Management Business Unit specializing in data center automation.


Return to ONDotnet.com

Copyright © 2009 O'Reilly Media, Inc.