简体   繁体   English

如何隐藏Visual Studio中自定义工具生成的文件

[英]How to hide files generated by custom tool in Visual Studio

I would like the files generated by my custom tool to be hidden, but I cannot find any documentation on how this is done. 我想隐藏我的自定义工具生成的文件,但我找不到任何关于如何完成此操作的文档。

An example of what I'm looking for is WPF code behind files. 我正在寻找的一个例子是文件背后的WPF代码。 These files are not displayed in the Visual Studio project view, yet are compiled with the project and are available in IntelliSense. 这些文件不会显示在Visual Studio项目视图中,而是使用项目进行编译,并在IntelliSense中可用。 WPF code behind files (Window1.gics, for example), are generated by a custom tool. 文件后面的WPF代码(例如,Window1.gics)由自定义工具生成。

The solution is to create a Target that adds your files to the Compile ItemGroup rather than adding them explicitly in your .csproj file. 解决方案是创建一个Target,将您的文件添加到Compile ItemGroup,而不是在.csproj文件中显式添加它们。 That way Intellisense will see them and they will be compiled into your executable, but they will not show up in Visual Studio. 这样,Intellisense将会看到它们并将它们编译到您的可执行文件中,但它们不会显示在Visual Studio中。

Simple example 简单的例子

You also need to make sure your target is added to the CoreCompileDependsOn property so it will execute before the compiler runs. 您还需要确保将目标添加到CoreCompileDependsOn属性,以便它在编译器运行之前执行。

Here is an extremely simple example: 这是一个非常简单的例子:

<PropertyGroup>
  <CoreCompileDependsOn>$(CoreCompileDependsOn);AddToolOutput</CoreCompileDependsOn>
</PropertyGroup>

<Target Name="AddToolOutput">
  <ItemGroup>
    <Compile Include="HiddenFile.cs" />
  </ItemGroup>
</Target>

If you add this to the bottom of your .csproj file (just before </Project> ), your "HiddenFile.cs" will be included in your compilation even though it doesn't appear in Visual Studio. 如果将其添加到.csproj文件的底部(就在</Project>之前),则“HiddenFile.cs”将包含在您的编译中,即使它没有出现在Visual Studio中。

Using a separate .targets file 使用单独的.targets文件

Instead of placing this directly in your .csproj file, you would generally placed it in a separate .targets file surrounded by: 您通常将它放在单独的.targets文件中,而不是直接将其放在.csproj文件中,该文件包含在:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  ...
</Project>

and import into your .csproj with <Import Project="MyTool.targets"> . 并使用<Import Project="MyTool.targets"> .csproj。 A .targets file is recommended even for one-off cases because it separates your custom code from the stuff in .csproj that is maintained by Visual Studio. 即使是一次性案例,也建议使用.targets文件,因为它将自定义代码与Visual Studio维护的.csproj中的内容分开。

Constructing the generated filename(s) 构造生成的文件名

If you are creating a generalized tool and/or using a separate .targets file, you probably don't want to explicitly list each hidden file. 如果要创建通用工具和/或使用单独的.targets文件,则可能不希望显式列出每个隐藏文件。 Instead you want to generate the hidden file names from other settings in the project. 相反,您希望从项目中的其他设置生成隐藏文件名。 For example if you want all Resource files to have corresponding tool-generated files in the "obj" directory, your Target would be: 例如,如果您希望所有资源文件在“obj”目录中具有相应的工具生成文件,那么您的目标将是:

<Target Name="AddToolOutput">
  <ItemGroup>
    <Compile Include="@(Resource->'$(IntermediateOutputPath)%(FileName)%(Extension).g.cs')" />
  </ItemGroup>
</Target>

The "IntermediateOutputPath" property is what we all know as the "obj" directory, but if the end-user of your .targets has customized this your intermediate files will stil be found in the same place. “IntermediateOutputPath”属性是我们所知的“obj”目录,但如果.targets的最终用户已经自定义了这个,那么您的中间文件将在同一个地方找到。 If you prefer your generated files to be in the main project directory and not in the "obj" directory, you can leave this off. 如果您希望生成的文件位于主项目目录中而不是“obj”目录中,则可以将其保留为关闭状态。

If you want only some of the files of an existing item type to be processed by your custom tool? 如果您只想要自定义工具处理现有项类型的某些文件? For example, you may want to generate files for all Page and Resource files with a ".xyz" extension. 例如,您可能希望为所有具有“.xyz”扩展名的页面和资源文件生成文件。

<Target Name="AddToolOutput">
  <ItemGroup>
    <MyToolFiles Include="@(Page);@(Resource)" Condition="'%(Extension)'=='.xyz' />
    <Compile Include="@(MyToolFiles->'$(IntermediateOutputPath)%(FileName)%(Extension).g.cs')"/>
  </ItemGroup>
</Target>

Note that you can't use the metadata syntax like %(Extension) in a top-level ItemGroup but you can do so within a Target. 请注意,您不能在顶级ItemGroup中使用%(扩展)等元数据语法,但您可以在Target中执行此操作。

Using a custom item type (aka Build Action) 使用自定义项类型(又名构建操作)

The above processes files that have an existing item type such as Page, Resource, or Compile (Visual Studio calls this the "Build Action"). 上面的处理文件具有现有的项目类型,如页面,资源或编译(Visual Studio将其称为“构建操作”)。 If your items are a new kind of file you can use your own custom item type. 如果您的商品是新类型的商品,则可以使用自己的自定义商品类型。 For example if your input files are called "Xyz" files, your project file can define "Xyz" as a valid item type: 例如,如果您的输入文件被称为“Xyz”文件,则您的项目文件可以将“Xyz”定义为有效的项类型:

<ItemGroup>
  <AvailableItemName Include="Xyz" />
</ItemGroup>

after which Visual Studio will allow you to select "Xyz" in the Build Action in the file's properties, resulting in this being added to your .csproj: 之后,Visual Studio将允许您在文件属性的Build Action中选择“Xyz”,从而将其添加到.csproj中:

<ItemGroup>
  <Xyz Include="Something.xyz" />
</ItemGroup>

Now you can use the "Xyz" item type to create the filenames for tool output, just as we did previously with the "Resource" item type: 现在,您可以使用“Xyz”项类型为工具输出创建文件名,就像之前使用“Resource”项类型一样:

<Target Name="AddToolOutput">
  <ItemGroup>
    <Compile Include="@(Xyz->'$(IntermediateOutputPath)%(FileName)%(Extension).g.cs')" />
  </ItemGroup>
</Target>

When using a custom item type you can cause your items to also be handled by built-in mechanisms by mapping them to another item type (aka Build Action). 使用自定义项目类型时,您可以通过将项目映射到另一个项目类型(也称为构建操作)来使您的项目也由内置机制处理。 This is useful if your "Xyz" files are really .cs files or .xaml or if they need to be made 如果您的“Xyz”文件确实是.cs文件或.xaml,或者如果需要它们,则此选项非常有用

EmbeddedResources. EmbeddedResources。 For example you can cause all files with "Build Action" of Xyz to also be compiled: 例如,您可以编译具有Xyz“Build Action”的所有文件:

<ItemGroup>
  <Compile Include="@(Xyz)" />
</ItemGroup>

Or if your "Xyz" source files should be stored as embedded resources, you can express it this way: 或者,如果您的“Xyz”源文件应存储为嵌入式资源,您可以这样表达:

<ItemGroup>
  <EmbeddedResource Include="@(Xyz)" />
</ItemGroup>

Note that the second example won't work if you put it inside the Target, since the target isn't evaluated until just before the core compile. 请注意,如果将其放在Target中,则第二个示例将不起作用,因为直到核心编译之前才对目标进行求值。 To make this work inside a Target you have to list the target name in PrepareForBuildDependsOn property instead of CoreCompileDependsOn. 要在Target中进行此工作,您必须在PrepareForBuildDependsOn属性中列出目标名称而不是CoreCompileDependsOn。

Invoking your custom code generator from MSBuild 从MSBuild调用自定义代码生成器

Having gone as far as creating a .targets file, you might consider invoking your tool directly from MSBuild rather than using a separate pre-build event or Visual Studio's flawed "Custom Tool" mechanism. 除了创建.targets文件之外,您可以考虑直接从MSBuild调用工具,而不是使用单独的预构建事件或Visual Studio有缺陷的“自定义工具”机制。

To do this: 去做这个:

  1. Create a Class Library project with a reference to Microsoft.Build.Framework 创建一个类库项目,引用Microsoft.Build.Framework
  2. Add the code to implement your custom code generator 添加代码以实现自定义代码生成器
  3. Add a class that implements ITask, and in the Execute method call your custom code generator 添加一个实现ITask的类,并在Execute方法中调用自定义代码生成器
  4. Add a UsingTask element to your .targets file, and in your target add a call to your new task 在.targets文件中添加一个UsingTask元素,并在目标中添加对新任务的调用

Here is all you need to implement ITask: 以下是实现ITask所需的全部内容:

public class GenerateCodeFromXyzFiles : ITask
{
  public IBuildEngine BuildEngine { get; set; }
  public ITaskHost HostObject { get; set; }

  public ITaskItem[] InputFiles { get; set; }
  public ITaskItem[] OutputFiles { get; set; }

  public bool Execute()
  {
    for(int i=0; i<InputFiles.Length; i++)
      File.WriteAllText(OutputFiles[i].ItemSpec,
        ProcessXyzFile(
          File.ReadAllText(InputFiles[i].ItemSpec)));
  }

  private string ProcessXyzFile(string xyzFileContents)
  {
    // Process file and return generated code
  }
}

And here is the UsingTask element and a Target that calls it: 这里是UsingTask元素和一个调用它的Target:

<UsingTask TaskName="MyNamespace.GenerateCodeFromXyzFiles" AssemblyFile="MyTaskProject.dll" />


<Target Name="GenerateToolOutput">

  <GenerateCodeFromXyzFiles
      InputFiles="@(Xyz)"
      OutputFiles="@(Xyz->'$(IntermediateOutputPath)%(FileName)%(Extension).g.cs')">

    <Output TaskParameter="OutputFiles" ItemGroup="Compile" />

  </GenerateCodeFromXyzFiles>
</Target>

Note that this target's Output element places the list of output files directly into Compile, so there is no need to use a separate ItemGroup to do this. 请注意,此目标的Output元素将输出文件列表直接放入Compile中,因此无需使用单独的ItemGroup来执行此操作。

How the old "Custom Tool" mechanism is flawed and why not to use it 旧的“自定义工具”机制是如何存在缺陷的,为什么不使用它

A note on Visual Studio's "Custom Tool" mechanism: In NET Framework 1.x we didn't have MSBuild, so we had to rely on Visual Studio to build our projects. 关于Visual Studio的“自定义工具”机制的注释:在.NET Framework 1.x中,我们没有MSBuild,因此我们不得不依赖Visual Studio来构建我们的项目。 In order to get Intellisense on generated code, Visual Studio had a mechanism called "Custom Tool" that can be set in the Properties window on a file. 为了在生成的代码上获取Intellisense,Visual Studio有一个名为“自定义工具”的机制,可以在文件的“属性”窗口中进行设置。 The mechanism was fundamentally flawed in several ways, which is why it was replaced with MSBuild targets. 该机制在几个方面存在根本缺陷,这就是它被MSBuild目标取代的原因。 Some of the problems with the "Custom Tool" feature were: “自定义工具”功能的一些问题是:

  1. A "Custom Tool" constructs the generated file whenever the file is edited and saved, not when the project is compiled. 每当编辑和保存文件时,“自定义工具”都会构造生成的文件,而不是在编译项目时。 This means that anything modifying the file externally (such as a revision control system) doesn't update the generated file and you often get stale code in your executable. 这意味着在外部修改文件的任何内容(例如修订控制系统)都不会更新生成的文件,并且您经常会在可执行文件中获得过时的代码。
  2. The output of a "Custom Tool" had to be shipped with your source tree unless your recipient also had both Visual Studio and your "Custom Tool". 除非您的收件人同时拥有Visual Studio和“自定义工具”,否则“自定义工具”的输出必须随源树一起提供。
  3. The "Custom Tool" had to be installed in the registry and couldn't simply be referenced from the project file. “自定义工具”必须安装在注册表中,不能简单地从项目文件中引用。
  4. The output of the "Custom Tool" is not stored in the "obj" directory. “自定义工具”的输出未存储在“obj”目录中。

If you are using the old "Custom Tool" feature, I strongly recommend you switch to using a MSBuild task. 如果您使用旧的“自定义工具”功能,我强烈建议您切换到使用MSBuild任务。 It works well with Intellisense and allows you to build your project without even installing Visual Studio (all you need is NET Framework). 它可以很好地与Intellisense一起使用,并允许您在不安装Visual Studio的情况下构建项目(您只需要.NET Framework)。

When will your custom build task run? 您的自定义构建任务何时运行?

In general your custom build task will run: 通常,您的自定义构建任务将运行:

  • In the background when Visual Studio opens the solution, if the generated file is not up to date 在Visual Studio打开解决方案的后台,如果生成的文件不是最新的
  • In the background any time you save one of the input files in Visual Studio 在后台随时保存Visual Studio中的一个输入文件
  • Any time you build, if the generated file is not up to date 如果生成的文件不是最新的,那么无论何时构建
  • Any time you rebuild 任何时候你重建

To be more precise: 更确切地说:

  1. An IntelliSense incremental build is run when Visual Studio starts and every time any file is saved within Visual Studio. Visual Studio启动时以及每次在Visual Studio中保存任何文件时都会运行IntelliSense增量构建。 This will run your generator if the output file is missing any of the input files are newer than the generator output. 如果输出文件丢失,这将运行您的生成器任何输入文件都比生成器输出更新。
  2. A regular incremental build is run whenever you use any "Build" or "Run" command in Visual Studio (including the menu options and pressing F5), or when you run "MSBuild" from the command line. 只要在Visual Studio中使用任何“构建”或“运行”命令(包括菜单选项并按F5),或从命令行运行“MSBuild”,就会运行常规增量构建。 Like the IntelliSense incremental build, It will also only run your generator if the generated file is not up to date 与IntelliSense增量构建一样,如果生成的文件不是最新的,它也将仅运行您的生成器
  3. A regular full build is run whenever you use any of the "Rebuild" commands in Visual Studio, or when you run "MSBuild /t:Rebuild" from the command line. 只要在Visual Studio中使用任何“重建”命令,或者从命令行运行“MSBuild / t:Rebuild”,就会运行常规完整构建。 It will always run your generator if there are any inputs or outputs. 如果有任何输入或输出,它将始终运行您的发电机。

You may want to force your generator to run at other times, such as when some environment variable changes, or force it to run synchronously rather in the background. 您可能希望强制您的生成器在其他时间运行,例如某些环境变量更改时,或强制它在后台同步运行。

  • To cause the generator to re-run even when no input files have changed, the best way is usually to add an additional Input to your Target which is a dummy input file stored in the "obj" directory. 要使生成器重新运行,即使没有输入文件已更改,最好的方法通常是向目标添加一个额外的输入,这是一个存储在“obj”目录中的虚拟输入文件。 Then whenever an environment variable or some external setting changes that should force your generator tool to re-run, simply touch this file (ie. create it or update its modified date). 然后,每当环境变量或某些外部设置发生变化时,应该强制生成器工具重新运行,只需触摸此文件(即创建它或更新其修改日期)。

  • To force the generator to run synchronously rather than waiting for IntelliSense to run it in the background, just use MSBuild to build your particular target. 要强制生成器同步运行而不是等待IntelliSense在后台运行它,只需使用MSBuild构建您的特定目标。 This could be as simple as executing "MSBuild /t:GenerateToolOutput", or VSIP may provide a build-in way to call custom build targets. 这可以像执行“MSBuild / t:GenerateToolOutput”一样简单,或者VSIP可以提供调用自定义构建目标的内置方式。 Alternatively you could simply invoke the Build command and wait for it to complete. 或者,您只需调用Build命令并等待它完成。

Note that "Input files" in this section refers to whatever is listed in the "Inputs" attribute of the Target element. 请注意,本节中的“输入文件”是指Target元素的“Inputs”属性中列出的内容。

Final notes 最后的笔记

You may get warnings from Visual Studio that it doesn't know whether to trust your custom tool .targets file. 您可能会收到来自Visual Studio的警告,它不知道是否信任您的自定义工具.targets文件。 To fix this, add it to the HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0\\MSBuild\\SafeImports registry key. 要解决此问题,请将其添加到HKEY_LOCAL_MACHINE \\ SOFTWARE \\ Microsoft \\ VisualStudio \\ 9.0 \\ MSBuild \\ SafeImports注册表项。

Here is a summary of what an actual .targets file would look like with all the pieces in place: 以下是所有部分的实际.targets文件的概述:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup>
    <CoreCompileDependsOn>$(CoreCompileDependsOn);GenerateToolOutput</CoreCompileDependsOn>
  </PropertyGroup>

  <UsingTask TaskName="MyNamespace.GenerateCodeFromXyzFiles" AssemblyFile="MyTaskProject.dll" />


  <Target Name="GenerateToolOutput" Inputs="@(Xyz)" Outputs="@(Xyz->'$(IntermediateOutputPath)%(FileName)%(Extension).g.cs')">

    <GenerateCodeFromXyzFiles
        InputFiles="@(Xyz)"
        OutputFiles="@(Xyz->'$(IntermediateOutputPath)%(FileName)%(Extension).g.cs')">

      <Output TaskParameter="OutputFiles" ItemGroup="Compile" />

    </GenerateCodeFromXyzFiles>
  </Target>

</Project>

Please let me know if you have any questions or there is anything here you didn't understand. 如果您有任何问题或者您有任何不明白的地方,请告诉我。

To hide items from Visual Studio add a Visible metadata property to the item. 要从Visual Studio隐藏项目,请向项目添加Visible元数据属性。 The InProject metadata apparently does this too. InProject元数据显然也是这样做的。

Visible: http://msdn.microsoft.com/en-us/library/ms171468(VS.90).aspx 可见: http//msdn.microsoft.com/en-us/library/ms171468(VS.90).aspx

InProject: http://blogs.msdn.com/b/jomo_fisher/archive/2005/01/25/360302.aspx InProject: http//blogs.msdn.com/b/jomo_fisher/archive/2005/01/25/360302.aspx

<ItemGroup>
  <Compile Include="$(AssemblyInfoPath)">
    <!-- either: -->
    <InProject>false</InProject>
    <!-- or: -->
    <Visible>false</Visible>
  </Compile>
</ItemGroup>

The only way I know to do it is to add the generated file to have a dependency on the file you want it hidden behind - in the proj file. 我知道这样做的唯一方法是在proj文件中添加生成的文件以依赖于您希望它隐藏在后面的文件。

For example: 例如:

 <ItemGroup>
    <Compile Include="test.cs" />
    <Compile Include="test.g.i.cs">
      <DependentUpon>test.cs</DependentUpon>
    </Compile>
  </ItemGroup>

If you removed the DependentUpon element then the file shows up beside the other file instead of behind it ... how does your generator add the files? 如果您删除了DependentUpon元素,那么该文件会显示在另一个文件旁边而不是它后面...您的生成器如何添加文件? can you walk us through the use case and how you would like it to work? 你能告诉我们用例以及你希望它如何工作吗?

I think you want to look here: http://msdn.microsoft.com/en-us/library/ms171453.aspx . 我想你想看看这里: http//msdn.microsoft.com/en-us/library/ms171453.aspx

Specifically, the "Creating Items During Execution" section. 具体来说,“执行期间创建项目”部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何部署visual studio自定义工具? - How to deploy a visual studio custom tool? 如何创建自定义工具以在Visual Studio 2010中生成代码? - How to create a custom tool to generate code in Visual Studio 2010? 如何在 Visual Studio 中寻址/调用我的自定义工具 window - How to adress/ call my custom tool window in Visual Studio 如何在 Visual Studio 中以编程方式在第一个位置显示自定义工具窗口 - How to display custom tool window at the first position, programmatically in visual studio 如何使用Visual Studio 2017注册“自定义工具”以使其工作? - How to register “custom tool” with Visual Studio 2017 to make it work? 如何在Visual Studio的发布配置文件中包含动态生成的文件 - How to include dynamically generated files in Visual Studio's publish profile 生成文件的 Visual Studio 代码分析 - Visual studio code analysis for generated files 在Visual Studio中自动隐藏工具窗口的快捷方式是什么? - What is the shortcut to auto hide a Tool Window in Visual Studio? 是否可以隐藏用Visual Studio sdk创建项目时生成的window? - Is it possible to hide the window generated when creating a project with Visual studio sdk? 如何在Visual Studio 2015/2017的自定义工具窗口中创建窗口表单? - How to create window form inside custom tool window in visual studio 2015/2017?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM