为什么修改项目输出目录会导致:IOException未处理“无法找到资源'app.xaml'". [英] Why does modifying project output directories cause: IOException was unhandled "Cannot locate resource 'app.xaml'."

查看:62
本文介绍了为什么修改项目输出目录会导致:IOException未处理“无法找到资源'app.xaml'".的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了将项目设置合并到C ++和C#项目的属性表中,构造了以下属性表:

In an attempt to consolidate project settings into property sheets for both C++ and C# projects, the following property sheet was constructed:

<?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可执行项目不是很好,因为使用上面的属性表运行应用程序会导致臭名昭著:

This property sheet will move all build output to a separate location OutputRelativePath (defined in separate property sheet or directly in project file) outside directories that contain source code for easier cleanup etc. However, after setting this up and build works fine and all unit tests work fine, it was clear that a WPF executable project was not fine, since running the application with above property sheet results in the infamous:

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

为什么更改输出路径会导致此错误?以及如何确定原因是项目构建输出路径?可以在生成的代码中看到吗?我找不到?这不是一个错误吗?

Why does changing the output paths result in this error? And how can it be determined that the cause is project build output paths? Can this be seen in generated code? I could not find it? And isn't this a bug?

注意:仅当 IntermediateOutputPath 包含 BaseIntermediateOutputPath 时,才能使用以下属性表.

NOTE: Using the following property sheet works, but only if IntermediateOutputPath contains BaseIntermediateOutputPath.

<?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属性或类似属性.

So it appears, that somehow it is expected that output paths contain the AssemblyName properties or similar.

另一个组件中XAML样式的更新:如果这些内容也适用于xaml ResourceDictionary,例如- Brushes.xaml-位于另一个程序集中,该程序集也更改了OutputPath,这也会引发异常:

UPDATE FOR XAML STYLES IN ANOTHER ASSEMBLY: The same applies to xaml ResourceDictionary if these - e.g. Brushes.xaml - are located in another assembly and this assembly has changed the OutputPath also, this also throws an exception:

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

因此,总的来说,输出位置会更改xaml资源名称,因此无法以某种方式在运行时发现它们.奇怪的是,在设计时这不是问题...

So all in all it appears output location changes the xaml resource names so these cannot be discovered at runtime, somehow. The odd thing is it is not a problem at design time...

更新:最小化重现异常的步骤:

UPDATE: Minimal steps to reproduce the exception:

打开Visual Studio 2013

Open Visual Studio 2013

创建新的C#项目WPF应用程序,例如XamlIntermediateOutputPathBug

Create new C# project WPF Application e.g. XamlIntermediateOutputPathBug

卸载项目

编辑项目文件

在第一个PropertyGroup之后,将新的PropertyGroup插入为:

After first PropertyGroup insert new PropertyGroup as:

<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>  

删除其余PropertyGroup中的OutputPath属性,例如

Delete OutputPath properties in remaining PropertyGroups e.g.

<OutputPath>bin\Debug\</OutputPath>  

和:

<OutputPath>bin\Release\</OutputPath>  

这将在开始时为mainwindow.xaml抛出IOException.这是由于$(AssemblyName).g.resources嵌入式资源被赋予以下名称:

This should then throw an IOException on start for mainwindow.xaml. This is due to the $(AssemblyName).g.resources embedded resource is given the following name:

.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来解决此问题(请参见

as can be seen with ildasm.exe and opening the MANIFEST for the assembly. As can also be seen the normal resources also gets a wrong name with the output path prefixed. This can, however, be fixed by setting the LogicalName in the project file for this resource (see MissingManifestResourceException when running tests after building with MSBuild (.mresource has path in manifest)). This does not appear to be possible for xaml resources...

查看了配置后,我注意到我在OutputPathIntermediateOutputPath的末尾使用了/,删除了它们似乎可以起作用的内容,请参见下文:

Having looked at the configuration I noticed I use / at the end of the OutputPath and IntermediateOutputPath, removing these it appears to work, see below:

<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必须带有反斜杠,否则您将收到有关此警告.

I find this rather curious... any insight into why this would be the case or if this is actually true is appreciated. Note that the C++ IntDir and OutDir instead must have a trailing backslash, otherwise you will get warnings about this.

推荐答案

将MSBuild输出的详细程度设置为诊断"很快就会发现问题的根源:

Setting the MSBuild output verbosity to "Diagnostic" quickly revealed the source of the problem:

1>   (TaskId:21)
1>  Microsoft (R) Build Task 'ResourcesGenerator' Version '4.0.30319.33440 built by: FX45W81RTMREL'. (TaskId:21)
1>  Copyright (C) Microsoft Corporation 2005. All rights reserved. (TaskId:21)
1>  
1>   (TaskId:21)
1>  Generating .resources file: '..\Build/Obj_Exe/WpfApplication8_AnyCPU_Debug/WpfApplication8.g.resources'... (TaskId:21)
1>  Reading Resource file: 'C:\Users\hpass_000\Projects\Build\Obj_Exe\WpfApplication8_AnyCPU_Debug\MainWindow.baml'... (TaskId:21)
1>  Resource ID is 'mainwindow.baml'. (TaskId:21)
1>  Generated .resources file: '..\Build/Obj_Exe/WpfApplication8_AnyCPU_Debug/WpfApplication8.g.resources'. 

请注意路径名中正斜杠和反斜杠的混合使用. Windows本身知道如何很好地处理路径名中的正斜杠.但是在其他软件中通常缺少该功能,而在资源生成器任务中却缺少该功能.这需要使用真正的反斜杠作为路径分隔符,正斜杠在资源名称中有效.修复:

Note the mix of forward and backward slashes in the path names. Windows itself knows how to handle forward slashes in path names well. But that capability is often lacking in other software, it is lacking in the resource generator task. Which requires a true backslash as a path separator, a forward slash is valid in a resource name. Fix:

 <OutputPath>$(OutputRelativePath)\$(AssemblyName)_$(Platform)_$(Configuration)\</OutputPath>
 <BaseIntermediateOutputPath>$(OutputRelativePath)\Obj_Exe\$(AssemblyName)_$(Platform)</BaseIntermediateOutputPath>
 <IntermediateOutputPath>$(BaseIntermediateOutputPath)_$(Configuration)\</IntermediateOutputPath>

换句话说,我只是将/替换为\.解决了问题.

In other words, I simply replaced / with \. Which solved the problem.

这篇关于为什么修改项目输出目录会导致:IOException未处理“无法找到资源'app.xaml'".的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆