9

プロジェクト設定を C++ プロジェクトと C# プロジェクトの両方のプロパティ シートに統合するために、次のプロパティ シートが作成されました。

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!--
      Trying to support both C++ and C# projects by introducing derived 
      properties and setting the appropriate output properties.
  -->
  <PropertyGroup Label="UserMacros">
    <ProjectOrAssemblyName Condition="'$(AssemblyName)'==''">$(ProjectName)</ProjectOrAssemblyName>
    <ProjectOrAssemblyName Condition="'$(ProjectName)'==''">$(AssemblyName)</ProjectOrAssemblyName>
    <ShortPlatform Condition="'$(Platform)'=='Win32'">x86</ShortPlatform>
    <ShortPlatform Condition="'$(Platform)'=='x86'">x86</ShortPlatform>
    <ShortPlatform Condition="'$(Platform)'=='x64'">x64</ShortPlatform>
    <ShortPlatform Condition="'$(Platform)'=='AnyCPU'">AnyCPU</ShortPlatform>
  </PropertyGroup>
  <PropertyGroup>
    <OutputPath>$(OutputRelativePath)/$(ProjectOrAssemblyName)_$(ShortPlatform)_$(Configuration)/</OutputPath>        
    <BaseIntermediateOutputPath>$(OutputRelativePath)/Obj_Exe/$(ProjectOrAssemblyName)_$(ShortPlatform)</BaseIntermediateOutputPath>
    <IntermediateOutputPath>$(BaseIntermediateOutputPath)_$(Configuration)/</IntermediateOutputPath>
    <IntDir>$(IntermediateOutputPath)</IntDir>
    <OutDir>$(OutputPath)</OutDir>
  </PropertyGroup>
</Project>

このプロパティ シートは、すべてのビルド出力を別の場所に移動します。OutputRelativePath (別のプロパティ シートで定義されるか、プロジェクト ファイルで直接定義されます) は、クリーンアップなどを容易にするために、ソース コードを含むディレクトリの外にあります。上記のプロパティ シートでアプリケーションを実行すると悪名高い結果が得られるため、WPF 実行可能プロジェクトが適切でないことは明らかでした。

IOException was unhandled "Cannot locate resource 'app.xaml'."

出力パスを変更するとこのエラーが発生するのはなぜですか? また、原因がプロジェクト ビルドの出力パスにあると判断するにはどうすればよいでしょうか。これは生成されたコードで確認できますか? 私はそれを見つけることができませんでしたか?そして、これはバグではありませんか?

注: 次のプロパティ シートを使用しても機能しますが、IntermediateOutputPathBaseIntermediateOutputPathが含まれている場合に限られます。

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <OutputPath>$(OutputRelativePath)/$(AssemblyName)_$(Platform)_$(Configuration)</OutputPath>
    <BaseIntermediateOutputPath>$(OutputRelativePath)/Obj_Exe/$(AssemblyName)_$(Platform)</BaseIntermediateOutputPath>
    <IntermediateOutputPath>$(BaseIntermediateOutputPath)_$(Configuration)</IntermediateOutputPath>
  </PropertyGroup>
</Project>

そのため、どういうわけか、出力パスに AssemblyName プロパティなどが含まれていることが予想されるようです。

別のアセンブリの XAML スタイルの更新: これら (Brushes.xaml など) が別のアセンブリにあり、このアセンブリが OutputPath も変更した場合、xaml ResourceDictionary にも同じことが適用されます。これも例外をスローします。

XamlParseException was unhandled for set property Source 
with InnerException "Cannot locate resource 'Brushes.xaml'" 

全体として、出力場所が xaml リソース名を変更するように見えるため、これらは実行時に何らかの方法で検出できません。奇妙なことに、設計時には問題はありません...


更新: 例外を再現するための最小限の手順:

Visual Studio 2013 を開く

新しい C# プロジェクト WPF アプリケーションを作成します。例: XamlIntermediateOutputPathBug

プロジェクトのアンロード

プロジェクトファイルの編集

最初の PropertyGroup の後に、新しい PropertyGroup を次のように挿入します。

<PropertyGroup>
  <OutputRelativePath>$(ProjectDir)..\Build</OutputRelativePath>
  <OutputPath>$(OutputRelativePath)/$(AssemblyName)_$(Platform)_$(Configuration)/</OutputPath>
  <BaseIntermediateOutputPath>$(OutputRelativePath)/Obj_Exe/$(AssemblyName)_$(Platform)</BaseIntermediateOutputPath>
  <IntermediateOutputPath>$(BaseIntermediateOutputPath)_$(Configuration)/</IntermediateOutputPath>
  <IntDir>$(IntermediateOutputPath)</IntDir>
  <OutDir>$(OutputPath)</OutDir>
</PropertyGroup>  

OutputPath残りの PropertyGroups のプロパティを 削除します。

<OutputPath>bin\Debug\</OutputPath>  

と:

<OutputPath>bin\Release\</OutputPath>  

IOExceptionこれにより、 on start for がスローされmainwindow.xamlます。これは、$(AssemblyName).g.resources埋め込みリソースに次の名前が付けられているためです。

.mresource public 'Build/Obj_Exe/XamlIntermediateOutputPathBug_AnyCPU_Debug/XamlIntermediateOutputPathBug.g.resources' as Build_Obj_Exe_XamlIntermediateOutputPathBug_AnyCPU_Debug_XamlIntermediateOutputPathBug.g.resources
{
  // Offset: 0x00000000 Length: 0x000003BC
}
.mresource public 'Build/Obj_Exe/XamlIntermediateOutputPathBug_AnyCPU_Debug/XamlIntermediateOutputPathBug.Properties.Resources.resources' as Build_Obj_Exe_XamlIntermediateOutputPathBug_AnyCPU_Debug_XamlIntermediateOutputPathBug.Properties.Resources.resources
{
  // Offset: 0x000003C0 Length: 0x000000B4
}

で見られるように、アセンブリildasm.exeの を開きます。MANIFEST見られるように、通常のリソースも、出力パスがプレフィックスとして付けられた間違った名前を取得します。LogicalNameただし、これは、このリソースのプロジェクト ファイルで を設定することで修正できます ( MSBuild でビルドした後にテストを実行する場合の MissingManifestResourceException を参照してください (.mresource has path in manifest) )。これは、xaml リソースでは可能ではないようです...

and/の最後で使用していることに気付いた構成を調べたところ、これらを削除すると機能しているように見えます。以下を参照してください。OutputPathIntermediateOutputPath

<PropertyGroup>
  <OutputRelativePath>$(ProjectDir)..\Build</OutputRelativePath>
  <OutputPath>$(OutputRelativePath)/$(AssemblyName)_$(Platform)_$(Configuration)</OutputPath>
  <BaseIntermediateOutputPath>$(OutputRelativePath)/Obj_Exe/$(AssemblyName)_$(Platform)</BaseIntermediateOutputPath>
  <IntermediateOutputPath>$(BaseIntermediateOutputPath)_$(Configuration)</IntermediateOutputPath>
  <IntDir>$(IntermediateOutputPath)/</IntDir>
  <OutDir>$(OutputPath)/</OutDir>
</PropertyGroup>  

これはかなり興味深いと思います...なぜこれが当てはまるのか、またはこれが実際に真実であるかどうかについての洞察をいただければ幸いです。C++IntDirOutDir代わりにバックスラッシュを末尾に付ける必要があることに注意してください。そうしないと、これに関する警告が表示されます。


4

2 に答える 2

1

WinFX および Xaml ターゲットは、Xaml が現在のプロジェクト内にある型を参照するときに、バックグラウンドでいくつかのハック/マジックを実行します。このビルド タスク中に、wpf.csproj が tempfilename.tmp_proj にコピーされ、アセンブリ参照に関連するいくつかのノードが削除され、ファイルが IntermediateOutputPath にコンパイルされます。これにより、Xaml コンパイラは一時アセンブリ内の型を参照できます。

于 2013-12-16T23:06:40.057 に答える