Have you ever been working on a project and found yourself constantly copying and pasting code between files to maintain consistency (such as comment preambles, disclaimers, (even code snippets! - ok, I'd recommend against that one!) etc). It can get quite tedious and error-prone, especially if what you're pasting has a bug, misprint, or something that needs to change universally. If you've ever had occasion to, upon adding a new file to a VS project, go through and rearrange all of the code to fit your standards and add in your comments (and waste hours upon hours doing so), then creating a custom template is for you. Using the proper jargon: creating a custom project item is for you.
Creating custom templates isn't an entirely trivial endeavor as you may know if you've tried it, but it's not overly complex. It involves creating (or editing) a .vsz (Wizard) file, a .vsdir file, and customizing your template files. This process involves navigating several directories and making tiny changes in each one.
The game changes a little if you're trying to add a WebForm to a web project, as I discovered while spending an hour churning over what seemed like it should have worked. The reason for my frustration is that VS.NET will, while accepting my .aspx template code, generate its own .aspx.cs code. In fact, it bases it's code on the C:\Program Files\Microsoft Visual Studio .NET 2003\VC#\DesignerTemplates\1033\NewWebFormCode.cs. I didn't want to go in and edit that file (except for making a few standards-abiding changes) because that would affect every page on every website that I develop, and that's too far-reaching for my tastes.
Here's what I did. Note that all directories that I reference are found in C:\Program Files\Microsoft Visual Studio .NET 2003\VC#\ as subdirectories. Also, the example templates, er, project items that I created are for a website called DevTracker.
1) Navigate to \CSharpProjectItems and create my wizard file called CSharpAddDevTrackerWebFormWiz.vsz. The contents of this file:
VSWIZARD 7.0
Wizard=VsWizard.VsWizardEngine.7.1
Param="WIZARD_NAME = CSharpAddDevTrackerWebFormWiz"
Param="WIZARD_UI = FALSE"
Param="PROJECT_TYPE = CSPROJ"
The VsWizard.VsWizardEngine.7.1 is the ProgId (yes, back to COM) of the VS.NET-provided IDTWizard implementation - which saves me the trouble of having to create my own wizard - I'll just hijack the plane already in the runway as it gets me off the ground faster. In fact, that's the recommended practice in this case.
2) In the \CSharpProjectItems\WebProjectItems folder create a DevstoneWebProjectItems.vsdir file. The contents of the .vsdir file:
..\CSharpAddDevTrackerWebFormWiz.vsz|{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}|DevTracker WebForm|1|A webform for the Devstone DevTracker Website|{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}|4534|0|DevTrackerWebForm.aspx
For a description on the format of the .vsdir files, check out this link. Basically, each line in the file is pipe (|) delimited. Suffice it to say, the first parameter references the .vsz file we created. The second param (the GUID) identifies the C# extensibility library (also used later as an identifier for the dll so we can extract the same icon as used for WebForms). The third parameter is the short description that appears along with the icon. The fourth parameter is the ordinal position of the icon within the 'Add Project Item' dialog. Then we have the long description, the GUID, the icon resource identifier, a zero
, and the default name to use for the to-be-added file.
3) Navigate to the \CSharpProjectItems\WebProjectItems\UI folder and create a DevstoneUI.vsdir file. I chose to do this rather than edit the extant ui.vsdir so I can place all of my custom project items therein and will be able to copy my directory tree over the C# folder and not run the risk of overwriting any files. It's great that the VS.NET IDE automatically picks up all .vsdir files rather than looking for specific ones! The contents of the .vsdir file:
..\..\CSharpAddDevTrackerWebFormWiz.vsz|{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}|DevTracker WebForm|1|A webform for the Devstone DevTracker Website|{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}|4534|0|DevTrackerWebForm.aspx
You'll probably see a lot of similarities to the previously created file in #2.
4) Within the \VC#Wizards directory, create a subdirectory called CSharpAddDevTrackerWebFormWiz. This name should match what you entered in the .vsz file in step #1 as the WIZARD_NAME.
5) It is within this new folder that the script file and templates get created - well, in subfolders. The easiest thing to do is to copy files that already exist (such as those from the CSharpAddWebFormWiz folder). Then you should have \Scripts\1033 and \Templates\1033 folders with some files.
6) Feel free to delete the Templates.inf file from \Templates\1033 - it's not needed. In fact it will screw you up when overriding VS.NET's default behavior of auto-generating the code-behind files.
7) Edit your WebForm1.aspx file as necessary (I renamed mine to DevTrackerWebForm1.aspx).
8) Now it's time to create your code-behind file. The best thing to do is to copy the NewWebFormCode.cs mentioned above and rename it (e.g. DevTrackerWebForm1.aspx.cs). At this point you're not done.
9) The \Scripts\1033\default.js file is the code that drives (sets up) the process of replacing [!output] tags in your source. In order to override the code-behind behavior we have to edit this file. That's because the default.js file provided for WebForms is written to handle just one file. The underlying functionality behind all default.js files is actually found within the script \VC#Wizards\1033\common.js. Fortunately for me
, I didn't have to scour this too much. I found a great article by Chris Sells that identifies how to do what I've already talked about to some depth. I took his default.js file and tweaked it to match my needs and I'm now ready to go.
All in all, it's not that bad, but it doesn't seem too well documented and can be a bit disconcerting to a newcomer to the template, dang!, project item arena.