I've built a t4 template to output multiple files, but I need these files to be embedded content.
Does t4 offer an out-of-the-box method of doing this?
If not, might it be possible to modify the project file by switching each file's <Content>
element to an <EmbeddedResource>
element?
Here's how I set a ProjectItem
to be an embedded resource: In the T4 template I have a function which takes the Project
object and a FileInfo
object representing the T4 template itself - there may be a simpler method but I obtained the template FileInfo
using...
var templateFileInfo = new FileInfo(this.Host.TemplateFile);
The template FileInfo
is used because we need the generated files (my T4 template outputs multiple files) which are generated 'under' the template file in the solution.
[Really, what I want here is a ProjectItem
representing the template, so that I can loop over the auto-generated children. If there's a better way of doing this, please comment.]
Once I have the ProjectItem
objects representing each of the T4-generated files, I enumerate each Properties
collection until I find the "BuildAction"
property for that ProjectItem
; this is then set as "Embedded Resource" using a constant.
private void SetGeneratedFilesAsEmbeddedResources(Project project, FileInfo templateFileInfo)
{
const string propBuildAction = "BuildAction";
var generatedProjectItems = GetGeneratedProjectItems(project, templateFileInfo).ToList();
foreach (var generatedProjectItem in generatedProjectItems)
{
var props = generatedProjectItem.Properties;
if ((VSLangProj.prjBuildAction)props.Item(propBuildAction).Value != VSLangProj.prjBuildAction.prjBuildActionEmbeddedResource)
{
props.Item(propBuildAction).Value = VSLangProj.prjBuildAction.prjBuildActionEmbeddedResource;
}
}
}
private IEnumerable<ProjectItem> GetGeneratedProjectItems(Project project, FileInfo templateFileInfo)
{
var templateParentFolder = GetTemplateParentFolder(project, templateFileInfo);
foreach (ProjectItem item in templateParentFolder.ProjectItems)
{
if (item.Kind != EnvDTE.Constants.vsProjectItemKindPhysicalFile || item.Name != templateFileInfo.Name)
{
continue;
}
foreach (ProjectItem generatedItem in item.ProjectItems)
{
yield return generatedItem;
}
}
}
private ProjectItem GetTemplateParentFolder(Project project, FileInfo templateFileInfo)
{
var containingFolderName = templateFileInfo.Directory.Name;
foreach (ProjectItem item in project.ProjectItems)
{
if (item.Kind == EnvDTE.Constants.vsProjectItemKindPhysicalFolder && item.Name == containingFolderName)
{
return item;
}
}
throw new Exception($"Cannot execute {templateFileInfo.Name} - Unable to locate the \"{containingFolderName}\" folder at the root level.");
}