[英]How to hide files generated by custom tool in Visual Studio
我想隐藏我的自定义工具生成的文件,但我找不到任何关于如何完成此操作的文档。
我正在寻找的一个例子是文件背后的WPF代码。 这些文件不会显示在Visual Studio项目视图中,而是使用项目进行编译,并在IntelliSense中可用。 文件后面的WPF代码(例如,Window1.gics)由自定义工具生成。
解决方案是创建一个Target,将您的文件添加到Compile ItemGroup,而不是在.csproj文件中显式添加它们。 这样,Intellisense将会看到它们并将它们编译到您的可执行文件中,但它们不会显示在Visual Studio中。
简单的例子
您还需要确保将目标添加到CoreCompileDependsOn
属性,以便它在编译器运行之前执行。
这是一个非常简单的例子:
<PropertyGroup>
<CoreCompileDependsOn>$(CoreCompileDependsOn);AddToolOutput</CoreCompileDependsOn>
</PropertyGroup>
<Target Name="AddToolOutput">
<ItemGroup>
<Compile Include="HiddenFile.cs" />
</ItemGroup>
</Target>
如果将其添加到.csproj文件的底部(就在</Project>
之前),则“HiddenFile.cs”将包含在您的编译中,即使它没有出现在Visual Studio中。
使用单独的.targets文件
您通常将它放在单独的.targets文件中,而不是直接将其放在.csproj文件中,该文件包含在:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
...
</Project>
并使用<Import Project="MyTool.targets">
.csproj。 即使是一次性案例,也建议使用.targets文件,因为它将自定义代码与Visual Studio维护的.csproj中的内容分开。
构造生成的文件名
如果要创建通用工具和/或使用单独的.targets文件,则可能不希望显式列出每个隐藏文件。 相反,您希望从项目中的其他设置生成隐藏文件名。 例如,如果您希望所有资源文件在“obj”目录中具有相应的工具生成文件,那么您的目标将是:
<Target Name="AddToolOutput">
<ItemGroup>
<Compile Include="@(Resource->'$(IntermediateOutputPath)%(FileName)%(Extension).g.cs')" />
</ItemGroup>
</Target>
“IntermediateOutputPath”属性是我们所知的“obj”目录,但如果.targets的最终用户已经自定义了这个,那么您的中间文件将在同一个地方找到。 如果您希望生成的文件位于主项目目录中而不是“obj”目录中,则可以将其保留为关闭状态。
如果您只想要自定义工具处理现有项类型的某些文件? 例如,您可能希望为所有具有“.xyz”扩展名的页面和资源文件生成文件。
<Target Name="AddToolOutput">
<ItemGroup>
<MyToolFiles Include="@(Page);@(Resource)" Condition="'%(Extension)'=='.xyz' />
<Compile Include="@(MyToolFiles->'$(IntermediateOutputPath)%(FileName)%(Extension).g.cs')"/>
</ItemGroup>
</Target>
请注意,您不能在顶级ItemGroup中使用%(扩展)等元数据语法,但您可以在Target中执行此操作。
使用自定义项类型(又名构建操作)
上面的处理文件具有现有的项目类型,如页面,资源或编译(Visual Studio将其称为“构建操作”)。 如果您的商品是新类型的商品,则可以使用自己的自定义商品类型。 例如,如果您的输入文件被称为“Xyz”文件,则您的项目文件可以将“Xyz”定义为有效的项类型:
<ItemGroup>
<AvailableItemName Include="Xyz" />
</ItemGroup>
之后,Visual Studio将允许您在文件属性的Build Action中选择“Xyz”,从而将其添加到.csproj中:
<ItemGroup>
<Xyz Include="Something.xyz" />
</ItemGroup>
现在,您可以使用“Xyz”项类型为工具输出创建文件名,就像之前使用“Resource”项类型一样:
<Target Name="AddToolOutput">
<ItemGroup>
<Compile Include="@(Xyz->'$(IntermediateOutputPath)%(FileName)%(Extension).g.cs')" />
</ItemGroup>
</Target>
使用自定义项目类型时,您可以通过将项目映射到另一个项目类型(也称为构建操作)来使您的项目也由内置机制处理。 如果您的“Xyz”文件确实是.cs文件或.xaml,或者如果需要它们,则此选项非常有用
EmbeddedResources。 例如,您可以编译具有Xyz“Build Action”的所有文件:
<ItemGroup>
<Compile Include="@(Xyz)" />
</ItemGroup>
或者,如果您的“Xyz”源文件应存储为嵌入式资源,您可以这样表达:
<ItemGroup>
<EmbeddedResource Include="@(Xyz)" />
</ItemGroup>
请注意,如果将其放在Target中,则第二个示例将不起作用,因为直到核心编译之前才对目标进行求值。 要在Target中进行此工作,您必须在PrepareForBuildDependsOn属性中列出目标名称而不是CoreCompileDependsOn。
从MSBuild调用自定义代码生成器
除了创建.targets文件之外,您可以考虑直接从MSBuild调用工具,而不是使用单独的预构建事件或Visual Studio有缺陷的“自定义工具”机制。
去做这个:
UsingTask
元素,并在目标中添加对新任务的调用 以下是实现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
}
}
这里是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>
请注意,此目标的Output元素将输出文件列表直接放入Compile中,因此无需使用单独的ItemGroup来执行此操作。
旧的“自定义工具”机制是如何存在缺陷的,为什么不使用它
关于Visual Studio的“自定义工具”机制的注释:在.NET Framework 1.x中,我们没有MSBuild,因此我们不得不依赖Visual Studio来构建我们的项目。 为了在生成的代码上获取Intellisense,Visual Studio有一个名为“自定义工具”的机制,可以在文件的“属性”窗口中进行设置。 该机制在几个方面存在根本缺陷,这就是它被MSBuild目标取代的原因。 “自定义工具”功能的一些问题是:
如果您使用旧的“自定义工具”功能,我强烈建议您切换到使用MSBuild任务。 它可以很好地与Intellisense一起使用,并允许您在不安装Visual Studio的情况下构建项目(您只需要.NET Framework)。
您的自定义构建任务何时运行?
通常,您的自定义构建任务将运行:
更确切地说:
您可能希望强制您的生成器在其他时间运行,例如某些环境变量更改时,或强制它在后台同步运行。
要使生成器重新运行,即使没有输入文件已更改,最好的方法通常是向目标添加一个额外的输入,这是一个存储在“obj”目录中的虚拟输入文件。 然后,每当环境变量或某些外部设置发生变化时,应该强制生成器工具重新运行,只需触摸此文件(即创建它或更新其修改日期)。
要强制生成器同步运行而不是等待IntelliSense在后台运行它,只需使用MSBuild构建您的特定目标。 这可以像执行“MSBuild / t:GenerateToolOutput”一样简单,或者VSIP可以提供调用自定义构建目标的内置方式。 或者,您只需调用Build命令并等待它完成。
请注意,本节中的“输入文件”是指Target元素的“Inputs”属性中列出的内容。
最后的笔记
您可能会收到来自Visual Studio的警告,它不知道是否信任您的自定义工具.targets文件。 要解决此问题,请将其添加到HKEY_LOCAL_MACHINE \\ SOFTWARE \\ Microsoft \\ VisualStudio \\ 9.0 \\ MSBuild \\ SafeImports注册表项。
以下是所有部分的实际.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>
如果您有任何问题或者您有任何不明白的地方,请告诉我。
要从Visual Studio隐藏项目,请向项目添加Visible
元数据属性。 InProject
元数据显然也是这样做的。
可见: 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
<ItemGroup>
<Compile Include="$(AssemblyInfoPath)">
<!-- either: -->
<InProject>false</InProject>
<!-- or: -->
<Visible>false</Visible>
</Compile>
</ItemGroup>
我知道这样做的唯一方法是在proj文件中添加生成的文件以依赖于您希望它隐藏在后面的文件。
例如:
<ItemGroup>
<Compile Include="test.cs" />
<Compile Include="test.g.i.cs">
<DependentUpon>test.cs</DependentUpon>
</Compile>
</ItemGroup>
如果您删除了DependentUpon元素,那么该文件会显示在另一个文件旁边而不是它后面...您的生成器如何添加文件? 你能告诉我们用例以及你希望它如何工作吗?
我想你想看看这里: http : //msdn.microsoft.com/en-us/library/ms171453.aspx 。
具体来说,“执行期间创建项目”部分。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.