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.
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 |
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.
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.
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.
|
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 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.
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.
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
|
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 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.
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:
Having pretty much figured out what makes the standard wizards tick, let's start creating our own.
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:
VSWIZARD 7.0
Wizard=VsWizard.VsWizardEngine.7.1
Param="WIZARD_NAME = CSharpAddCMSimpleBusinessClassWizard"
Param="WIZARD_UI = FALSE"
Param="PROJECT_TYPE = CSPROJ"..\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
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.