Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
230 changes: 230 additions & 0 deletions docs/templates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
# Template Support

This document explains how to include Visual Studio project templates and item templates in your VSIX extension using CodingWithCalvin.VsixSdk.

## Background

The built-in VSIX Manifest Designer in Visual Studio cannot enumerate SDK-style projects when adding template assets. This is because the designer uses legacy DTE extenders that are registered for the old project system, not the Common Project System (CPS) used by SDK-style projects.

Additionally, SDK-style projects don't define the `TemplateProjectOutputGroup` and `ItemTemplateOutputGroup` MSBuild output groups that VSSDK expects for template assets.

This SDK provides MSBuild-based template support that bypasses these limitations entirely.

## Item Types

The SDK provides four item types for including templates:

| Item Type | Description |
|-----------|-------------|
| `VsixProjectTemplate` | A folder containing a `.vstemplate` file for a project template |
| `VsixItemTemplate` | A folder containing a `.vstemplate` file for an item template |
| `VsixTemplateZip` | A pre-built template zip file |
| `VsixTemplateReference` | Reference a template folder from another project |

## Auto-Discovery

By default, the SDK automatically discovers templates in your project:

- **Project templates**: Any subfolder in `ProjectTemplates/` containing a `.vstemplate` file
- **Item templates**: Any subfolder in `ItemTemplates/` containing a `.vstemplate` file

### Example Project Structure

```
MyExtension/
MyExtension.csproj
source.extension.vsixmanifest
ProjectTemplates/
MyProjectTemplate/
MyProjectTemplate.vstemplate
MyProject.csproj
Class1.cs
ItemTemplates/
MyItemTemplate/
MyItemTemplate.vstemplate
MyClass.cs
```

With this structure, no additional configuration is needed. The SDK will:
1. Find the templates automatically
2. Zip each template folder during build
3. Include the zips in the VSIX at `ProjectTemplates/` and `ItemTemplates/`

### Disabling Auto-Discovery

To disable automatic template discovery:

```xml
<PropertyGroup>
<EnableDefaultVsixTemplateItems>false</EnableDefaultVsixTemplateItems>
</PropertyGroup>
```

### Changing Default Folders

To use different folder names:

```xml
<PropertyGroup>
<VsixProjectTemplatesFolder>Templates\Projects</VsixProjectTemplatesFolder>
<VsixItemTemplatesFolder>Templates\Items</VsixItemTemplatesFolder>
</PropertyGroup>
```

## Manual Template Configuration

### Folder-Based Templates

If your templates are in non-standard locations, add them explicitly:

```xml
<ItemGroup>
<VsixProjectTemplate Include="MyTemplates\ConsoleApp" />
<VsixItemTemplate Include="MyTemplates\NewClass" />
</ItemGroup>
```

### Pre-Built Template Zips

If you have pre-built template zip files:

```xml
<ItemGroup>
<VsixTemplateZip Include="Templates\MyTemplate.zip" TemplateType="Project" />
<VsixTemplateZip Include="Templates\MyItem.zip" TemplateType="Item" />
</ItemGroup>
```

### Template References

To include a template from another project in your solution:

```xml
<ItemGroup>
<VsixTemplateReference Include="..\MyTemplateProject\MyTemplateProject.csproj"
TemplateType="Project"
TemplatePath="Templates\MyProjectTemplate" />
</ItemGroup>
```

The `TemplatePath` is relative to the referenced project's directory.

## Manifest Configuration

Visual Studio requires `<Content>` entries in your `.vsixmanifest` to register templates. Add these to your manifest:

```xml
<Content>
<ProjectTemplate Path="ProjectTemplates" />
<ItemTemplate Path="ItemTemplates" />
</Content>
```

The SDK will emit warnings if you have templates defined but missing manifest entries:
- **VSIXSDK011**: Project templates defined but no `<ProjectTemplate>` in manifest
- **VSIXSDK012**: Item templates defined but no `<ItemTemplate>` in manifest

## Target Subfolders

To organize templates into subfolders within the VSIX:

```xml
<ItemGroup>
<!-- Will be placed at ProjectTemplates/CSharp/ -->
<VsixProjectTemplate Include="ProjectTemplates\MyTemplate" TargetSubPath="CSharp" />

<!-- Will be placed at ItemTemplates/Web/ -->
<VsixItemTemplate Include="ItemTemplates\MyItem" TargetSubPath="Web" />
</ItemGroup>
```

## Complete Example

### Project File

```xml
<Project Sdk="CodingWithCalvin.VsixSdk/1.0.0">

<PropertyGroup>
<Version>1.0.0</Version>
</PropertyGroup>

<!-- Templates are auto-discovered, but you can add more explicitly -->
<ItemGroup>
<VsixTemplateReference Include="..\SharedTemplates\SharedTemplates.csproj"
TemplateType="Project"
TemplatePath="Templates\SharedProject" />
</ItemGroup>

</Project>
```

### Manifest File

```xml
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011">
<Metadata>
<Identity Id="MyExtension" Version="1.0.0" Language="en-US" Publisher="MyCompany" />
<DisplayName>My Extension</DisplayName>
<Description>Extension with templates</Description>
</Metadata>
<Installation>
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.0,19.0)">
<ProductArchitecture>amd64</ProductArchitecture>
</InstallationTarget>
</Installation>
<Content>
<ProjectTemplate Path="ProjectTemplates" />
<ItemTemplate Path="ItemTemplates" />
</Content>
</PackageManifest>
```

### Template File (.vstemplate)

```xml
<?xml version="1.0" encoding="utf-8"?>
<VSTemplate Version="3.0.0" Type="Project" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
<TemplateData>
<Name>My Project Template</Name>
<Description>A sample project template</Description>
<Icon>__TemplateIcon.ico</Icon>
<ProjectType>CSharp</ProjectType>
<DefaultName>MyProject</DefaultName>
<ProvideDefaultName>true</ProvideDefaultName>
</TemplateData>
<TemplateContent>
<Project File="MyProject.csproj" ReplaceParameters="true">
<ProjectItem ReplaceParameters="true">Class1.cs</ProjectItem>
</Project>
</TemplateContent>
</VSTemplate>
```

## Validation Warnings

| Code | Description |
|------|-------------|
| VSIXSDK010 | `VsixTemplateZip` item missing `TemplateType` metadata |
| VSIXSDK011 | Project templates defined but no `<ProjectTemplate>` in manifest |
| VSIXSDK012 | Item templates defined but no `<ItemTemplate>` in manifest |
| VSIXSDK013 | `VsixTemplateReference` item missing `TemplateType` metadata |
| VSIXSDK014 | `VsixTemplateReference` item missing `TemplatePath` metadata |

## Troubleshooting

### Templates not appearing in Visual Studio

1. Ensure your manifest has the appropriate `<Content>` entries
2. Check that the template zip files are included in the VSIX (open the .vsix as a zip)
3. Verify the `.vstemplate` file has correct `<ProjectType>` or `<TemplateGroupID>`
4. Reset the Visual Studio template cache: delete `%LocalAppData%\Microsoft\VisualStudio\<version>\ComponentModelCache`

### Build errors about missing template folders

Ensure the template folder exists and contains a `.vstemplate` file. For `VsixTemplateReference`, verify the `TemplatePath` is correct relative to the referenced project.

### Templates in wrong location in VSIX

Check the `TargetSubPath` metadata if you're using custom paths. By default, templates are placed directly in `ProjectTemplates/` or `ItemTemplates/`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace $rootnamespace$;

/// <summary>
/// Sample class created from item template.
/// </summary>
public class $fileinputname$
{
public $fileinputname$()
{
}

public void DoSomething()
{
// TODO: Implement your logic here
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<VSTemplate Version="3.0.0" Type="Item" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
<TemplateData>
<Name>Sample Class</Name>
<Description>A sample class item template</Description>
<ProjectType>CSharp</ProjectType>
<SortOrder>10</SortOrder>
<DefaultName>SampleClass.cs</DefaultName>
</TemplateData>
<TemplateContent>
<ProjectItem ReplaceParameters="true" TargetFileName="$fileinputname$.cs">SampleClass.cs</ProjectItem>
</TemplateContent>
</VSTemplate>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace $safeprojectname$;

class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello from $safeprojectname$!");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>$safeprojectname$</RootNamespace>
<AssemblyName>$safeprojectname$</AssemblyName>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<VSTemplate Version="3.0.0" Type="Project" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
<TemplateData>
<Name>Sample Console App</Name>
<Description>A sample console application project template</Description>
<ProjectType>CSharp</ProjectType>
<SortOrder>1000</SortOrder>
<DefaultName>SampleConsoleApp</DefaultName>
<ProvideDefaultName>true</ProvideDefaultName>
<CreateNewFolder>true</CreateNewFolder>
<LocationField>Enabled</LocationField>
<EnableLocationBrowseButton>true</EnableLocationBrowseButton>
</TemplateData>
<TemplateContent>
<Project File="SampleProject.csproj" ReplaceParameters="true">
<ProjectItem ReplaceParameters="true" TargetFileName="Program.cs">Class1.cs</ProjectItem>
</Project>
</TemplateContent>
</VSTemplate>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!--
For LOCAL DEVELOPMENT, this project uses Microsoft.NET.Sdk with
Directory.Build.props/targets to add VSIX SDK behavior.

When published, users would use:
<Project Sdk="CodingWithCalvin.VsixSdk/1.0.0">
-->
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<Version>1.0.0</Version>
<RootNamespace>SampleExtensionWithTemplates</RootNamespace>
<AssemblyName>SampleExtensionWithTemplates</AssemblyName>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.SDK" Version="17.*" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.VisualStudio.Shell;
using Task = System.Threading.Tasks.Task;

namespace SampleExtensionWithTemplates
{
/// <summary>
/// This is the class that implements the package exposed by this assembly.
/// </summary>
[PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]
[Guid(PackageGuidString)]
public sealed class SampleExtensionWithTemplatesPackage : AsyncPackage
{
/// <summary>
/// SampleExtensionWithTemplatesPackage GUID string.
/// </summary>
public const string PackageGuidString = "b2c3d4e5-f6a7-8901-bcde-f23456789012";

/// <summary>
/// Initialization of the package; this method is called right after the package is sited.
/// </summary>
protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress<ServiceProgressData> progress)
{
await base.InitializeAsync(cancellationToken, progress);

// When initialized asynchronously, switch to the main thread before accessing VS services
await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

// This extension provides project and item templates
// Templates are automatically discovered from ProjectTemplates/ and ItemTemplates/ folders
}
}
}
34 changes: 34 additions & 0 deletions samples/SampleExtensionWithTemplates/source.extension.vsixmanifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Id="SampleExtensionWithTemplates.b2c3d4e5-f6a7-8901-bcde-f23456789012" Version="1.0.0" Language="en-US" Publisher="Coding With Calvin" />
<DisplayName>Sample Extension With Templates</DisplayName>
<Description xml:space="preserve">A sample Visual Studio extension demonstrating template support with CodingWithCalvin.VsixSdk</Description>
<MoreInfo>https://github.com/CodingWithCalvin/VsixSdk</MoreInfo>
<Tags>sample, templates, vsix</Tags>
</Metadata>
<Installation>
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.0, 19.0)">
<ProductArchitecture>amd64</ProductArchitecture>
</InstallationTarget>
<InstallationTarget Id="Microsoft.VisualStudio.Professional" Version="[17.0, 19.0)">
<ProductArchitecture>amd64</ProductArchitecture>
</InstallationTarget>
<InstallationTarget Id="Microsoft.VisualStudio.Enterprise" Version="[17.0, 19.0)">
<ProductArchitecture>amd64</ProductArchitecture>
</InstallationTarget>
</Installation>
<Dependencies>
<Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="[4.7.2,)" />
</Dependencies>
<Prerequisites>
<Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[17.0,19.0)" DisplayName="Visual Studio core editor" />
</Prerequisites>
<Assets>
<Asset Type="Microsoft.VisualStudio.VsPackage" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%;PkgDefProjectOutputGroup|" />
</Assets>
<Content>
<ProjectTemplate Path="ProjectTemplates" />
<ItemTemplate Path="ItemTemplates" />
</Content>
</PackageManifest>
Loading