Click here to Skip to main content
6,822,123 members and growing! (17,423 online)
Email Password   helpLost your password?
Platforms, Frameworks & Libraries » .NET Framework » General     Advanced License: The Code Project Open License (CPOL)

Create Item Templates Which Have Nested Items

By Sarafian

A template creation method, implementing IWizard in order to add nested items in the solution
C# (C#2.0), .NET, Visual-Studio (VS2005)
Posted:25 Jan 2008
Updated:5 May 2008
Views:13,329
Bookmarked:14 times
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
5 votes for this article.
Popularity: 2.45 Rating: 3.50 out of 5
1 vote, 20.0%
1

2
1 vote, 20.0%
3
1 vote, 20.0%
4
2 votes, 40.0%
5

Introduction

Many of has have wondered how Visual Studio implements nesting of items in the solution explorer of items. In case I am not explaining myself well, I am talking about the nested appearance of the three items that represent a Form object:

  • Form1.cs
  • Form.Designer.cs
  • Form.resx

The post from my blog can be found here.

Background

Visual Studio 2005 does not have the functionality to choose several items and create a nesting schema. In order to do this, you must open the *.csproj file with your favorite editor and then do some stuff as described here.

I would expect Visual Studio 2008 to have implemented this feature, but it doesn't. So what can you do? One solution is to use the macro from delarou's blog. The idea is fairly simple but it was the only article I found that explained the know-how of how to tell Visual Studio programmatically to nest items. I couldn't have done without this post.

But macros were not my interest because usually nested items are a product of an insertion of a templated item. So in this article I will focus on how to achieve this when creating a custom template item with multiple items. For example, a type dataset.

An article about how to create a Custom Item Template can be found here.

I will get into depth with this process because there are many articles about this on the Internet. The only thing that I have to say is that the Custom Item Template file (MyTemplate.vstemplate) that describes the template and files to use, does not allow the <DependentUpon> attribute on each item in it.

So the only solution is to attach to the template, custom logic which is implemented in a class which implements the Microsoft.VisualStudio.TemplateWizard.IWizard interface and tell the MyTemplate.vstemplate to use the assembly that contains the file.

The only problem for this solution is that all template logic related assemblies must be located in gac so the related projects must be signed.

The Infrastructure

After much hard testing, I came up with a solution which requires from a class only to define the logic that separate nested items from their parent. This is achieved because template logic is defined in a class that inherits from Sarafian.Templates.NestedItemTemplateBase.Base which implements the IWizard interface.

This class stored privately which project is the parent and which are its children. While items are added to a project and sent to the template logic to be consumed, the template in the ProjectItemFinishedGenerating functions calls the abstract function GetProjectItemType and decides if it is a parent or nested.

public void ProjectItemFinishedGenerating(EnvDTE.ProjectItem projectItem)
{
    ProjectItemTypes type = GetProjectItemType(projectItem);
    switch (type)
    {
        case ProjectItemTypes.Parent:
            this.parentProjectItem = projectItem; 
            break;
        case ProjectItemTypes.Child:
            this.childrenProjectItems.Add(projectItem);
            break;
    }
}

Then when the template is finished, it adds the nested items to its parent like this:

public void RunFinished()
{
    foreach (EnvDTE.ProjectItem item in this.childrenProjectItems)
    {
    string filename = item.get_FileNames(0);
    this.parentProjectItem.ProjectItems.AddFromFile(filename);
    }
}

Because the project is required to be placed in the gac, this post-build event is defined:

"C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" 
    /if "$(TargetPath)"

Creating the Template

In the zip file above, I have implemented an example.

The template item I want to create consists of four files:

  • Example.cs
  • Example.Input.cs
  • Example.Output.cs
  • Example.Error.cs

Example.cs will be the parent and all others its children. So this is how it is done:

protected override ProjectItemTypes GetProjectItemType(EnvDTE.ProjectItem item)
{
    if (item.Name.IndexOf(".Input.cs") > 0)
    {
        return ProjectItemTypes.Child;
    }
    if (item.Name.IndexOf(".Output.cs") > 0)
    {
        return ProjectItemTypes.Child;
    }
    if (item.Name.IndexOf(".Error.cs") > 0)
    {
        return ProjectItemTypes.Child;
    }

    return ProjectItemTypes.Parent;

} 

It doesn't matter if they are totally different classes or partial. For practical reasons, the entire collection of files needed for the template zip file are placed in a directory called ExampleItem and are marked as Compile none and Copy if Newer in the properties of each one.

"C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" 
    /if "$(TargetPath)"
"C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" 
    /l "$(TargetName)"

After the first compilation, a public key token is generated that must be set only once in the MyTemplate.vstemplate file like this:

<WizardExtension>
    <Assembly>Sarafian.Templates.ExampleItemTemplate, Version=1.0.0.0, 
        Culture=neutral, PublicKeyToken=6df23c9c2e2f12af</Assembly>
    <FullClassName>Sarafian.Templates.ExampleItemTemplate.Template</FullClassName>
</WizardExtension>

After this, the template is ready to be used.

Points of Interest

Some things to keep in mind. Because Visual Studio uses a cached version of the gac, any change made to the binary aspect of the template requires the restart of Visual Studio that will use the template.

Debug cannot be done with traditional techniques but old techniques were used in order to understand what happens within an IWizard implemented class. This is what I have understood.

First of all ShouldAddProjectItem is called. If false is returned, then the file is never templated. This means that no parameters are replaced within it. The filepath has the value of the original file at this point.

After the replacement of custom parameters, ProjectItemFinishedGenerating is called. At this point, the item's Name is the generated one. For example, if I wish my template to be called Sarafian, then for the Example.Input.cs in the template, the item name is Sarafian.Input.cs.

After all files have been processed by the above function, BeforeOpeningFile is called which tells Visual Studio to open for editing the file. In this case, the item always corresponds to Example.cs.

Finally RunFinished is called.

The above sequence is followed when the template is Item Template and not Project Template.

More info can be found in this article by Ron Petrusha which proved very helpful for me.

History

  • 25th January, 2008: Initial post
  • 5th May, 2008: Added Solution for Visual Studio 2008
    Future implementations will have a command line that will dynamically generate the zip file for the template. Interestingly, I cannot find the command to use Windows zip functionality. Any comments or directions would be much appreciated.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Sarafian


Member
Alex Sarafian lives in Athens Greece and currently is working with Business scale application with .NET latest technologies

He has been developing applications for personal and friends usage with C++ using majorly Borland's various IDEs since 1994.
In 2002 began working for an R&D institute where he was introduced to C# which he worships ever since.

He has recently created a development blog http://sarafianalex.wordpress.com/

He loves core applications development and in his spare time he usualy "wastes" time in front of his media center pc watching sitcoms, preferable SCI-FI.
He wants to play chess but he can't find any real world players to hang out with.
Occupation: Software Developer (Senior)
Company: Orama Hellas
Location: Greece Greece

Other popular .NET Framework articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 10 of 10 (Total in Forum: 10) (Refresh)FirstPrevNext
GeneralCan't get it to work... PinmemberArif.Khan16:21 1 May '08  
GeneralRe: Can't get it to work... PinmemberArif.Khan20:13 1 May '08  
GeneralRe: Can't get it to work... PinmemberSarafian0:35 2 May '08  
GeneralRe: Can't get it to work... PinmemberSarafian0:34 2 May '08  
GeneralRe: Can't get it to work... PinmemberSarafian3:46 5 May '08  
GeneralDownload Link PinmemberSarafian5:11 23 Apr '08  
GeneralSource code missing PinmemberTBermudez5:10 23 Apr '08  
GeneralRe: Source code missing PinmemberSarafian6:32 23 Apr '08  
GeneralRe: Source code missing PinmemberSarafian0:03 24 Apr '08  
GeneralA Comment PinmemberSarafian7:20 2 Apr '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads.

PermaLink | Privacy | Terms of Use
Last Updated: 5 May 2008
Editor: Deeksha Shenoy
Copyright 2008 by Sarafian
Everything else Copyright © CodeProject, 1999-2010
Web22 | Advertise on the Code Project