Visual Studio project templates offer two ways of specifying template parameter values:
- In the .vstemplate file, using a CustomParameters section, as described here.
- Using a template wizard in order to specify run-time values in the IWizard.RunStarted method, as described here.
The problem is that these mechanisms don’t work as one would expect in the case of multi-project templates. The parameters specified in the root template are not picked up by the child project templates. I tried to find a workaround online but could not find anything. Finally, I came up with a workaround of my own.
My workaround requires that the root project template and the child project templates have template wizards.
For demonstration purposes, let’s assume that the root template has a RootTemplateWizard class assigned as the template wizard. Let’s also assume that the child project that needs parameters values from the root template has a ChildTemplateWizard class assigned as the template wizard. If your child project template does not already have a template wizard, then you need to add one in order to pick up parameter values from the root template.
The main thing that will allow the two wizard classes to communicate is the fact that for multi-project templates the solution/project creation is done within the same application domain. This means that static members from each of the two classes are viewable in both classes.
Let’s say that ChildTemplateWizard needs to specify a $MyInheritedParam$ value. This is done in the IWizard.RunStarted method by adding the value to the replacementsDictionary method parameter with the key “$MyInheritedParam$”. Because we’re anticipating the value being present in a static field, we use that field as the value in the replacementsDictionary, as indicated in the code below:
The value for the MyInheritedParam static field can be set from the RootTemplateWizard class, from its RunStarted method. The other IWizard methods are not suitable because they get called only after project generation is complete for all child projects. The code below illustrates setting the value for the static field.
It’s worth mentioning that RootTemplateWizard and ChildTemplateWizard don’t have to be placed in separate assemblies. If placed in the same assembly, you only have to install a single assembly in the GAC when installing the multi-project template.
P.S. While writing this post and looking up some links for documentation I stumbled upon a blog post where the same principle is used to transmit custom parameters to child project templates. This post did not appear when I was searching for an already existing solution and for me it was not immediately clear that it solved this issue.