35

カスタム ツールによって生成されたファイルを非表示にしたいのですが、その方法に関するドキュメントが見つかりません。

私が探しているものの例は、WPF コード ビハインド ファイルです。これらのファイルは Visual Studio プロジェクト ビューには表示されませんが、プロジェクトと共にコンパイルされ、IntelliSense で使用できます。WPF コード ビハインド ファイル (Window1.gics など) は、カスタム ツールによって生成されます。

4

4 に答える 4

69

解決策は、ファイルを.csprojファイルに明示的に追加するのではなく、ファイルをCompileItemGroupに追加するターゲットを作成することです。そうすれば、Intellisenseはそれらを認識し、実行可能ファイルにコンパイルされますが、VisualStudioには表示されません。

簡単な例

CoreCompileDependsOnまた、コンパイラが実行される前にターゲットが実行されるように、ターゲットがプロパティに追加されていることを確認する必要があります。

非常に簡単な例を次に示します。

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

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

これを.csprojファイルの最後(直前</Project>)に追加すると、「HiddenFile.cs」はVisual Studioに表示されなくても、コンパイルに含まれます。

別の.targetsファイルを使用する

これを.csprojファイルに直接配置する代わりに、通常、次のファイルで囲まれた別の.targetsファイルに配置します。

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

を使用して.csprojにインポートします<Import Project="MyTool.targets">。.targetsファイルは、Visual Studioによって維持される.csproj内のものからカスタムコードを分離するため、1回限りの場合でもお勧めします。

生成されたファイル名の作成

一般化されたツールを作成している場合や、個別の.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で%(Extension)のようなメタデータ構文を使用することはできませんが、Target内で使用できることに注意してください。

カスタムアイテムタイプの使用(別名ビルドアクション)

上記は、ページ、リソース、コンパイルなどの既存のアイテムタイプを持つファイルを処理します(Visual Studioではこれを「ビルドアクション」と呼びます)。アイテムが新しい種類のファイルである場合は、独自のカスタムアイテムタイプを使用できます。たとえば、入力ファイルが「Xyz」ファイルと呼ばれる場合、プロジェクトファイルは「Xyz」を有効なアイテムタイプとして定義できます。

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

その後、Visual Studioでは、ファイルのプロパティのビルドアクションで[Xyz]を選択できるようになり、これが.csprojに追加されます。

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

これで、「リソース」アイテムタイプで以前に行ったように、「Xyz」アイテムタイプを使用してツール出力用のファイル名を作成できます。

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

カスタムアイテムタイプを使用する場合、アイテムを別のアイテムタイプ(別名ビルドアクション)にマッピングすることにより、組み込みメカニズムによってアイテムを処理することもできます。これは、「Xyz」ファイルが実際に.csファイルまたは.xamlである場合、またはそれらを作成する必要がある場合に役立ちます。

EmbeddedResources。たとえば、Xyzの「ビルドアクション」を含むすべてのファイルをコンパイルすることもできます。

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

または、「Xyz」ソースファイルを埋め込みリソースとして保存する必要がある場合は、次のように表現できます。

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

2番目の例は、コアがコンパイルされる直前までターゲットが評価されないため、ターゲット内に配置すると機能しないことに注意してください。これをターゲット内で機能させるには、CoreCompileDependsOnではなくPrepareForBuildDependsOnプロパティにターゲット名をリストする必要があります。

MSBuildからカスタムコードジェネレーターを呼び出す

.targetsファイルの作成まで行ったら、別のビルド前イベントやVisual Studioの欠陥のある「カスタムツール」メカニズムを使用するのではなく、MSBuildから直接ツールを呼び出すことを検討してください。

これをする:

  1. Microsoft.Build.Frameworkへの参照を使用してクラスライブラリプロジェクトを作成します
  2. コードを追加して、カスタムコードジェネレーターを実装します
  3. ITaskを実装するクラスを追加し、Executeメソッドでカスタムコードジェネレーターを呼び出します
  4. UsingTask.targetsファイルに要素を追加し、ターゲットに新しいタスクへの呼び出しを追加します

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要素とそれを呼び出すターゲットです。

<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がなかったため、プロジェクトのビルドにはVisualStudioに依存する必要がありました。生成されたコードでIntellisenseを取得するために、Visual Studioには、ファイルの[プロパティ]ウィンドウで設定できる「カスタムツール」と呼ばれるメカニズムがありました。このメカニズムにはいくつかの点で根本的な欠陥があり、それがMSBuildターゲットに置き換えられた理由です。「カスタムツール」機能の問題のいくつかは次のとおりです。

  1. 「カスタムツール」は、プロジェクトのコンパイル時ではなく、ファイルが編集および保存されるたびに生成されたファイルを作成します。つまり、ファイルを外部で変更しても(リビジョン管理システムなど)、生成されたファイルは更新されず、実行可能ファイルに古いコードが含まれることがよくあります。
  2. 受信者がVisualStudioと「カスタムツール」の両方を持っていない限り、「カスタムツール」の出力はソースツリーと一緒に出荷する必要がありました。
  3. 「カスタムツール」はレジストリにインストールする必要があり、プロジェクトファイルから単純に参照することはできませんでした。
  4. 「カスタムツール」の出力は「obj」ディレクトリに保存されません。

古い「カスタムツール」機能を使用している場合は、MSBuildタスクの使用に切り替えることを強くお勧めします。Intellisenseとうまく連携し、Visual Studioをインストールしなくてもプロジェクトをビルドできます(必要なのはNET Frameworkだけです)。

カスタムビルドタスクはいつ実行されますか?

通常、カスタムビルドタスクは次のように実行されます。

  • Visual Studioがソリューションを開いたときのバックグラウンドで、生成されたファイルが最新でない場合
  • バックグラウンドで、入力ファイルの1つをVisualStudioに保存するときはいつでも
  • ビルドするときはいつでも、生成されたファイルが最新でない場合
  • 再構築するときはいつでも

より正確には:

  1. IntelliSenseインクリメンタルビルドは、Visual Studioの起動時、およびVisualStudio内にファイルが保存されるたびに実行されます。これにより、出力ファイルが欠落している場合にジェネレーターが実行されます。入力ファイルのいずれかがジェネレーターの出力よりも新しい場合です。
  2. Visual Studioで「ビルド」または「実行」コマンドを使用するとき(メニューオプションとF5キーを押すことを含む)、またはコマンドラインから「MSBuild」を実行するときはいつでも、通常のインクリメンタルビルドが実行されます。IntelliSenseインクリメンタルビルドと同様に、生成されたファイルが最新でない場合にのみジェネレーターを実行します
  3. Visual Studioで「再構築」コマンドのいずれかを使用するとき、またはコマンドラインから「MSBuild / t:Rebuild」を実行するときはいつでも、通常のフルビルドが実行されます。入力または出力がある場合は、常にジェネレーターを実行します。

環境変数が変更されたときなど、他の時間にジェネレーターを強制的に実行したり、バックグラウンドではなく同期的に実行したりすることができます。

  • 入力ファイルが変更されていない場合でもジェネレーターを再実行するには、通常、「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>

ご不明な点やご不明な点がございましたら、お気軽にお問い合わせください。

于 2010-06-19T04:31:29.743 に答える
20

Visual Studio から項目を非表示にするには、Visibleメタデータ プロパティを項目に追加します。メタInProjectデータも明らかにこれを行います。

表示: http://msdn.microsoft.com/en-us/library/ms171468(VS.90).aspx

プロジェクト内: 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>
于 2010-06-22T03:56:38.647 に答える
0

私が知っている唯一の方法は、生成されたファイルを追加して、背後に隠したいファイルに依存するようにすることです-projファイルに。

例えば:

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

DependentUpon 要素を削除すると、ファイルは他のファイルの後ろではなく横に表示されます...ジェネレーターはどのようにファイルを追加しますか? ユースケースと、それをどのように機能させたいかについて説明してもらえますか?

于 2010-06-14T00:36:44.463 に答える
0

ここを見たいと思います: http://msdn.microsoft.com/en-us/library/ms171453.aspx

具体的には、「実行中の項目の作成」セクションです。

于 2010-06-18T18:16:40.847 に答える