2017-09-01 81 views
1

我想在多輸出文件中解決方案文件夾在現有項目創建文件,T4模板的項目文件,基於tangible T4 Editor tutorial如何創建一個解決方案文件夾(而不是物理文件夾)

我有我的解決方案的結構如下:

/T4Templates 
    - T4TemplateProject **<--- my T4 Project** 
/Common 
    -Project.NameSpace.Common **<--- Want to create file in here** 
/Services 
    -Project.NameSpace.Services **<--- And create file in here** 

我的出發點是從ttincludefile以下摘錄:

/// <summary> 
/// Marks the end of the last file if there was one, and starts a new 
/// and marks this point in generation as a new file. 
/// </summary> 
/// <param name="name">Filename</param> 
/// <param name="projectName">Name of the target project for the new file.</param> 
/// <param name="folderName">Name of the target folder for the new file.</param> 
/// <param name="fileProperties">File property settings in vs for the new File</param> 
public void StartNewFile(string name, string projectName = "", 
    string folderName = "", FileProperties fileProperties = null) 
{ 
    if (String.IsNullOrWhiteSpace(name) == true) 
    { 
     throw new ArgumentException("name"); 
    } 

    CurrentBlock = new Block 
    { 
     Name = name, 
     ProjectName = projectName, 
     FolderName = folderName, 
     FileProperties = fileProperties ?? new FileProperties() 
    }; 
} 

/// <summary> 
/// Produce the template output files. 
/// </summary> 
public virtual IEnumerable<OutputFile> Process(bool split = true) 
{ 
    var list = new List<OutputFile>(); 

    if (split) 
    { 
     EndBlock(); 

     var headerText = _generationEnvironment.ToString(header.Start, header.Length); 
     var footerText = _generationEnvironment.ToString(footer.Start, footer.Length); 
     files.Reverse(); 

     foreach (var block in files) 
     { 
      var outputPath = VSHelper.GetOutputPath(dte, block, 
       Path.GetDirectoryName(_textTransformation.Host.TemplateFile)); //<-- exception bubbled up here 
      var fileName = Path.Combine(outputPath, block.Name); 
      var content = this.ReplaceParameter(headerText, block) + 
       _generationEnvironment.ToString(block.Start, block.Length) + 
       footerText; 

      var file = new OutputFile 
      { 
       FileName = fileName, 
       ProjectName = block.ProjectName, 
       FolderName = block.FolderName, 
       FileProperties = block.FileProperties, 
       Content = content 
      }; 

      CreateFile(file); 
      _generationEnvironment.Remove(block.Start, block.Length); 

      list.Add(file);  
     } 
    } 

    projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(list, null, null)); 
    this.CleanUpTemplatePlaceholders(); 
    var items = VSHelper.GetOutputFilesAsProjectItems(this.dte, list); 
    this.WriteVsProperties(items, list); 

    if (this.IsAutoIndentEnabled == true && split == true) 
    { 
     this.FormatProjectItems(items); 
    } 

    this.WriteLog(list); 

    return list; 
} 

private void FormatProjectItems(IEnumerable<EnvDTE.ProjectItem> items) 
{ 
    foreach (var item in items) 
    { 
     this._textTransformation.WriteLine(
     VSHelper.ExecuteVsCommand(this.dte, item, "Edit.FormatDocument")); 
     this._textTransformation.WriteLine("//-> " + item.Name); 
    } 
} 

private void WriteVsProperties(IEnumerable<EnvDTE.ProjectItem> items, 
    IEnumerable<OutputFile> outputFiles) 
{ 
    foreach (var file in outputFiles) 
    { 
     var item = items 
      .Where(p => p.Name == Path.GetFileName(file.FileName)) 
      .FirstOrDefault(); 
     if (item == null) continue; 

     if (String.IsNullOrEmpty(file.FileProperties.CustomTool) == false) 
     { 
      VSHelper.SetPropertyValue(
       item, "CustomTool", file.FileProperties.CustomTool); 
     } 

     if (String.IsNullOrEmpty(file.FileProperties.BuildActionString) == false) 
     { 
      VSHelper.SetPropertyValue(
       item, "ItemType", file.FileProperties.BuildActionString); 
     } 
    } 
} 

private string ReplaceParameter(string text, Block block) 
{ 
    if (String.IsNullOrEmpty(text) == false) 
    { 
     text = text.Replace("$filename$", block.Name); 
    } 

    foreach (var item in block.FileProperties.TemplateParameter.AsEnumerable()) 
    { 
     text = text.Replace(item.Key, item.Value); 
    } 

    return text; 
} 

/// <summary> 
/// Write log to the default output file. 
/// </summary> 
/// <param name="list"></param> 
private void WriteLog(IEnumerable<OutputFile> list) 
{ 
    this._textTransformation.WriteLine("// Generated helper templates"); 
    foreach (var item in templatePlaceholderList) 
    { 
     this._textTransformation.WriteLine(
      "// " + this.GetDirectorySolutionRelative(item));   
    } 

    this._textTransformation.WriteLine("// Generated items"); 
    foreach (var item in list) 
    { 
     this._textTransformation.WriteLine(
      "// " + this.GetDirectorySolutionRelative(item.FileName)); 
    } 
} 

/// <summary> 
/// Removes old template placeholders from the solution. 
/// </summary> 
private void CleanUpTemplatePlaceholders()  
{ 
    string[] activeTemplateFullNames = this.templatePlaceholderList.ToArray(); 
    string[] allHelperTemplateFullNames = VSHelper.GetAllSolutionItems(this.dte) 
     .Where(p => 
      p.Name == VSHelper.GetTemplatePlaceholderName(this.templateProjectItem)) 
     .Select(p => VSHelper.GetProjectItemFullPath(p)) 
     .ToArray(); 

    var delta = allHelperTemplateFullNames.Except(activeTemplateFullNames).ToArray(); 

    var dirtyHelperTemplates = VSHelper.GetAllSolutionItems(this.dte) 
     .Where(p => delta.Contains(VSHelper.GetProjectItemFullPath(p))); 

    foreach (ProjectItem item in dirtyHelperTemplates) 
    { 
     if (item.ProjectItems != null) 
     { 
      foreach (ProjectItem subItem in item.ProjectItems) 
      { 
       subItem.Remove(); 
      } 
     } 

     item.Remove(); 
    } 
} 

protected virtual void CreateFile(OutputFile file) 
{ 
    if (this.CanOverrideExistingFile == false && File.Exists(file.FileName) == true) 
    { 
     return; 
    } 

    if (IsFileContentDifferent(file)) 
    { 
     CheckoutFileIfRequired(file.FileName); 
     File.WriteAllText(file.FileName, file.Content, this.Encoding); 
    } 
} 

protected bool IsFileContentDifferent(OutputFile file) 
{ 
    return !(File.Exists(file.FileName) && File.ReadAllText(file.FileName) == file.Content); 
} 

private void CheckoutFileIfRequired(string fileName) 
{ 
    if (dte.SourceControl == null 
     || !dte.SourceControl.IsItemUnderSCC(fileName) 
      || dte.SourceControl.IsItemCheckedOut(fileName)) 
    { 
     return; 
    } 

    // run on worker thread to prevent T4 calling back into VS 
    checkOutAction.EndInvoke(checkOutAction.BeginInvoke(fileName, null, null)); 
} 

摘錄的第2部分:VSHelper類。我已經指出發生異常的地方並冒出泡沫。您可以搜索的字符串<-- exception

public class VSHelper 
{ 
    /// <summary> 
    /// Execute Visual Studio commands against the project item. 
    /// </summary> 
    /// <param name="item">The current project item.</param> 
    /// <param name="command">The vs command as string.</param> 
    /// <returns>An error message if the command fails.</returns> 
    public static string ExecuteVsCommand(EnvDTE.DTE dte, EnvDTE.ProjectItem item, params string[] command) 
    { 
     if (item == null) 
     { 
      throw new ArgumentNullException("item"); 
     } 

     string error = String.Empty; 

     try 
     { 
      EnvDTE.Window window = item.Open(); 
      window.Activate(); 

      foreach (var cmd in command) 
      { 
       if (String.IsNullOrWhiteSpace(cmd) == true) 
       { 
        continue; 
       } 

       EnvDTE80.DTE2 dte2 = dte as EnvDTE80.DTE2; 
       dte2.ExecuteCommand(cmd, String.Empty);  
      } 

      item.Save(); 
      window.Visible = false; 
      // window.Close(); // Ends VS, but not the tab :(
     } 
     catch (Exception ex) 
     { 
      error = String.Format("Error processing file {0} {1}", item.Name, ex.Message); 
     } 

     return error; 
    } 

    /// <summary> 
    /// Sets a property value for the vs project item. 
    /// </summary> 
    public static void SetPropertyValue(EnvDTE.ProjectItem item, string propertyName, object value) 
    { 
     EnvDTE.Property property = item.Properties.Item(propertyName); 
     if (property == null) 
     { 
      throw new ArgumentException(String.Format("The property {0} was not found.", propertyName)); 
     } 
     else 
     { 
      property.Value = value; 
     } 
    } 

    public static IEnumerable<ProjectItem> GetOutputFilesAsProjectItems(EnvDTE.DTE dte, IEnumerable<OutputFile> outputFiles) 
    { 
     var fileNames = (from o in outputFiles 
         select Path.GetFileName(o.FileName)).ToArray(); 

     return VSHelper.GetAllSolutionItems(dte).Where(f => fileNames.Contains(f.Name)); 
    } 

    public static string GetOutputPath(EnvDTE.DTE dte, Block block, string defaultPath) 
    { 
     if (String.IsNullOrEmpty(block.ProjectName) == true && String.IsNullOrEmpty(block.FolderName) == true) 
     { 
      return defaultPath; 
     } 

     EnvDTE.Project prj = null; 
     EnvDTE.ProjectItem item = null; 

     if (String.IsNullOrEmpty(block.ProjectName) == false) 
     { 
      prj = GetProject(dte, block.ProjectName); //<-- exception bubbled up here   
     } 

     if (String.IsNullOrEmpty(block.FolderName) == true && prj != null) 
     { 
      return Path.GetDirectoryName(prj.FullName); 
     } 
     else if (prj != null && String.IsNullOrEmpty(block.FolderName) == false) 
     { 
      item = GetAllProjectItemsRecursive(prj.ProjectItems).Where(i=>i.Name == block.FolderName).First(); 
     } 
     else if (String.IsNullOrEmpty(block.FolderName) == false) 
     { 
      item = GetAllProjectItemsRecursive(
       dte.ActiveDocument.ProjectItem.ContainingProject.ProjectItems). 
       Where(i=>i.Name == block.FolderName).First(); 
     } 

     if (item != null) 
     { 
      return GetProjectItemFullPath(item); 
     } 

     return defaultPath; 
    } 
    public static string GetTemplatePlaceholderName(EnvDTE.ProjectItem item) 
    { 
     return String.Format("{0}.txt4", Path.GetFileNameWithoutExtension(item.Name)); 
    } 

    public static EnvDTE.ProjectItem GetTemplateProjectItem(EnvDTE.DTE dte, OutputFile file, EnvDTE.ProjectItem defaultItem) 
    { 
     if (String.IsNullOrEmpty(file.ProjectName) == true && String.IsNullOrEmpty(file.FolderName) == true) 
     { 
      return defaultItem; 
     } 

     string templatePlaceholder = GetTemplatePlaceholderName(defaultItem); 
     string itemPath = Path.GetDirectoryName(file.FileName); 
     string fullName = Path.Combine(itemPath, templatePlaceholder); 
     EnvDTE.Project prj = null; 
     EnvDTE.ProjectItem item = null; 

     if (String.IsNullOrEmpty(file.ProjectName) == false) 
     { 
      prj = GetProject(dte, file.ProjectName);    
     } 

     if (String.IsNullOrEmpty(file.FolderName) == true && prj != null) 
     { 
      return FindProjectItem(prj.ProjectItems, fullName, true); 
     } 
     else if (prj != null && String.IsNullOrEmpty(file.FolderName) == false) 
     { 
      item = GetAllProjectItemsRecursive(prj.ProjectItems).Where(i=>i.Name == file.FolderName).First(); 
     } 
     else if (String.IsNullOrEmpty(file.FolderName) == false) 
     { 
      item = GetAllProjectItemsRecursive(
       dte.ActiveDocument.ProjectItem.ContainingProject.ProjectItems). 
       Where(i=>i.Name == file.FolderName).First(); 
     } 

     if (item != null) 
     { 
      return FindProjectItem(item.ProjectItems, fullName, true); 
     } 

     return defaultItem; 
    } 

    private static EnvDTE.ProjectItem FindProjectItem(EnvDTE.ProjectItems items, string fullName, bool canCreateIfNotExists) 
    { 
     EnvDTE.ProjectItem item = (from i in items.Cast<EnvDTE.ProjectItem>() 
            where i.Name == Path.GetFileName(fullName) 
            select i).FirstOrDefault(); 
     if (item == null) 
     { 
      File.CreateText(fullName); 
      item = items.AddFromFile(fullName); 
     } 

     return item; 
    } 

    public static EnvDTE.Project GetProject(EnvDTE.DTE dte, string projectName) 
    { 
     return GetAllProjects(dte).Where(p=>p.Name == projectName).First(); // <-- exception ORIGINATES HERE 
    } 

    public static IEnumerable<EnvDTE.Project> GetAllProjects(EnvDTE.DTE dte) 
    { 
     List<EnvDTE.Project> projectList = new List<EnvDTE.Project>(); 

     var folders = dte.Solution.Projects.Cast<EnvDTE.Project>().Where(p=>p.Kind == EnvDTE80.ProjectKinds.vsProjectKindSolutionFolder); 

     foreach (EnvDTE.Project folder in folders) 
     { 
      if (folder.ProjectItems == null) continue; 

      foreach (EnvDTE.ProjectItem item in folder.ProjectItems) 
      { 
       if (item.Object is EnvDTE.Project) 
        projectList.Add(item.Object as EnvDTE.Project); 
      } 
     } 

     var projects = dte.Solution.Projects.Cast<EnvDTE.Project>().Where(p=>p.Kind != EnvDTE80.ProjectKinds.vsProjectKindSolutionFolder); 

     if (projects.Count() > 0) 
      projectList.AddRange(projects); 

     return projectList; 
    } 

    public static EnvDTE.ProjectItem GetProjectItemWithName(EnvDTE.ProjectItems items, string itemName) 
    { 
     return GetAllProjectItemsRecursive(items).Cast<ProjectItem>().Where(i=>i.Name == itemName).First(); 
    } 

    public static string GetProjectItemFullPath(EnvDTE.ProjectItem item) 
    { 
     return item.Properties.Item("FullPath").Value.ToString(); 
    } 

    public static IEnumerable<EnvDTE.ProjectItem> GetAllSolutionItems(EnvDTE.DTE dte) 
    { 
     List<EnvDTE.ProjectItem> itemList = new List<EnvDTE.ProjectItem>(); 

     foreach (Project item in GetAllProjects(dte)) 
     { 
      if (item == null || item.ProjectItems == null) continue; 

      itemList.AddRange(GetAllProjectItemsRecursive(item.ProjectItems)); 
     } 

     return itemList; 
    } 

    public static IEnumerable<EnvDTE.ProjectItem> GetAllProjectItemsRecursive(EnvDTE.ProjectItems projectItems) 
    { 
     foreach (EnvDTE.ProjectItem projectItem in projectItems) 
     { 
      if (projectItem.ProjectItems == null) continue; 

      foreach (EnvDTE.ProjectItem subItem in GetAllProjectItemsRecursive(projectItem.ProjectItems)) 
      { 
       yield return subItem; 
      } 


      yield return projectItem; 
     } 
    } 
} 

我的模板:

<#@ template debug="true" hostSpecific="true" #> 
<#@ output extension=".cs" #> 
<#@ Assembly Name="System.Core" #> 
<#@ Assembly Name="System.Windows.Forms" #> 
<#@ import namespace="System" #> 
<#@ import namespace="System.IO" #> 
<#@ import namespace="System.Diagnostics" #> 
<#@ import namespace="System.Linq" #> 
<#@ import namespace="System.Collections" #> 
<#@ import namespace="System.Collections.Generic" #> 

<#@ include file="TemplateFileManagerV2.1.ttinclude" #> 
<# 
var manager = TemplateFileManager.Create(this); 
#> 

<# 
//This correctly generates a file in the local T4TemplateProject 
manager.StartNewFile("MyObject.cs"); 
#> 

<# 
//this fails 
manager.StartNewFile("MyObjectDto.cs","Project.NameSpace.Common","Common"); 
#> 

<#  
manager.Process(); 
#> 

我收到以下錯誤:

Severity Code Description Project File Line Suppression State Error Running transformation: System.InvalidOperationException: Sequence contains no elements

我已閱讀以下內容:

  1. http://t4-editor.tangible-engineering.com/blog/how-to-generate-multiple-output-files-from-a-single-t4-template.html
  2. How to create multiple output files from a single T4 template using Tangible Editor?

的T4例子是基於下述溶液結構: enter image description here

我想那裏有解決方案文件夾做同樣的: enter image description here

+0

你能看到哪一行引發異常嗎?你也可以發佈代碼CreateFile() –

+0

我已經更新了CreatFile()代碼及其依賴關係 – user919426

+0

對於引發異常的代碼,將不得不拆分代碼,因爲它超過了允許的行數 – user919426

回答

1

我已將您的代碼的相關部分縮減爲:

var projectList = dte.Solution.Projects 
    .Cast<EnvDTE.Project>() 
    .Where(p => p.Kind == EnvDTE80.ProjectKinds.vsProjectKindSolutionFolder) 
    .Where(folder => folder.ProjectItems != null) 
    .SelectMany(folder => folder.ProjectItems) 
    .Where(item => item.Object is EnvDTE.Project) 
    .Select(item => item.Object as EnvDTE.Project) 

var projects = dte.Solution.Projects.Cast<EnvDTE.Project>() 
    .Where(p => p.Kind != EnvDTE80.ProjectKinds.vsProjectKindSolutionFolder); 

projectList.Concat(projects) 
    .Where(p=>p.Name == projectName) 
    .First(); // <-- exception ORIGINATES HERE 

所以它看起來像p.Kind或p.Name不是你所期待的。

要進行調試,請循環使用dte.Solution.Projects及其所有子項目項目。輸出種類和名稱屬性。

+0

稍後將嘗試一下。無論哪種方式,感謝您閱讀所有代碼的努力,並且仔細琢磨! – user919426

相關問題