[VisualStudio]ビルド時のファイルコピー先をプロジェクト階層と違う場所にする

VisualStudio(というかMSBuildなんだけど)では、
ソースファイルでない任意のプロジェクトファイルについて
ソリューション エクスプローラーからビルドアクションを指定するときに
出力ディレクトリへのコピー有無を指定できる。

ただし、設定できるのはコピーするかどうかを決めるモードだけで、
コピー先のディレクトリを変えたりすることはできない。

例えば、以下のような構成で
Project Root — ProjName.csproj
        |- AClassFile.cs
        |- bin\
        |- obj\
        |- Properties\
        |- img\ — image.jpg

image.jpgをプロジェクトに追加して、プロパティの
「出力ディレクトリにコピー」を「常にコピーする」にしてリリースビルドすると、
ファイルはbin\Release\img\image.jpgにコピーされる。

このコピー先をたとえば、bin\Release\out\image.jpgにしたい場合。

ひとつの力技としては、プロジェクトのプロパティから
ビルドイベント>「ビルド後に実行するコマンド ライン」に

mkdir $(TargetDir)out
copy $(ProjectDir)img\image.jpg $(TargetDir)out\

のような感じで自前のコピー処理を入れてやるという手はある。
 

けど、もう少しシンプルな解決策がありました。

一度VisualStudioを閉じてから、.csprojをテキストエディタで開き、
image.jpgをインクルードしている部分を探す。

<ItemGroup>
  <Content Include="img\image.jpg">
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  </Content>
</ItemGroup>

これに以下の1行を追加。

<ItemGroup>
  <Content Include="img\image.jpg">
    <Link>out\image.jpg</Link>
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  </Content>
</ItemGroup>

これだけで期待通りの動きになる。

Link要素は本来、既存の項目をリンクとしてプロジェクトに追加する際に使用されるもので
要素の値は追加先のディレクトリパスだ。
なので上の書き方だと、img\image.jpgに配置されているファイルを
一旦リンクとしてout\image.jpgに追加し、それがビルド時にコピーされるので
出力先がbin\Release\out\image.jpgになる。

ただ欠点は、VisualStudioのソリューション エクスプローラーで見ても
こんな書き方になっていることがわからないことかな。

build-copy

上のようにimg\image.jpgのファイルはプロジェクトに含まれていないように見える。
そして(VS2013以降だけ?)outフォルダがプロジェクトディレクトリ内にも勝手に生成されるが、
中身は空のままなので、なんだこのフォルダは??ってなるかも。