XAML(WPF)设计师在解析应用程序资源方面缺乏一致或有意义的方式。

3
我经常遇到设计问题,XAML设计师(WPF的“xdesproc”)会以一种方式显示我的控件,但在运行时则完全不同。通常这些差异是因为在运行时使用的静态资源(在应用程序级别)与设计师中使用的不同。
当一个大型解决方案由多个项目组成(其中大多数是用户控件库,而其中几个是启动项目(应用程序、测试用例等))时,这种情况发生得最多。
在使用VS编辑库中的用户控件时,我从Blend中发现了一个技巧,可以在项目中引入“DesignTimeResources.xaml”文件,Visual Studio会将其视为补充到用户控件本身中使用的资源中(就像它们在该用户控件的逻辑树中被找到一样)。
我认为这个技巧足以使我能够在设计师中省去应用程序级别的资源。然而,“DesignTimeResources.xaml”并没有解决我所有的问题。xdesproc也不认为这是足够的应用程序级别资源的来源(即xdesproc可能会同时将其加载为其应用程序级别资源和用户控件的逻辑树中的资源)。
通过监视xdesproc,我发现它的行为非常不寻常,以便找到它想要用于应用程序级别资源的东西。它使用的搜索机制似乎并不是很明确定义。如果不小心,它要么完全忽略建立任何应用程序级别资源,要么随机从外部解决方案中找到的一个项目中选择(这个项目可能与用户控件库无关,但被找到并被使用,因为它包含一个恰好是“Application/”的项目项)。
有人能告诉我在编辑用户控件时,xdesproc是否应该有一种定义明确的方式来查找应用程序级别的资源?我的解决方法是大量的琢磨和调整,涉及到卸载项目。我暂时卸载了所有带有“Application”元素的解决方案中的项目,除了一个。否则,xdesproc可能会随意选择其中一个并开始愉快地将其用作其应用级别资源。它似乎没有限制自己只使用VS IDE中的当前启动项目。
如果有什么指针可以帮助我理解xdesproc认为它应该使用什么应用程序资源,我将不胜感激。我怀疑它被编程成“聪明”的“能够正常工作”。在许多情况下,它可能确实有效,但当它失灵时就不行了。
3个回答

4

在经过多次试验和错误之后,这是我所发现的。当你编辑一个库中的用户控件时,设计师将扫描整个解决方案,并根据许多复杂的标准尝试为你找到应用程序级别的资源。这个搜索并不像我最初认为的那么随机。它只会找到并使用资源,如果它们:

  • 在未卸载且输出类型为“Windows应用程序”的项目中
  • 资源必须包含在项目中的“Application”成员中(System.Windows.Application)
  • 此成员的构建操作必须是“ApplicationDefinition”(即不能将构建操作设置为“Page”,与单独的静态Main结合使用)
  • 必须存在指向您正在使用的用户控件库的直接项目引用。
  • 如果有符合上述标准的多个候选项,则设计师将使用被配置为当前启动项目的那个。

考虑到设计师搜索其应用程序级别资源的广泛范围,有一些令开发人员感到沮丧的结果:

  • 如果你所使用的用户控件库包含本地的“DesignTimeResources.xaml”,你可能会合理地认为设计师会使用这些资源,并且它们将“胜出”于在扫描解决方案时找到的任何应用程序定义。不幸的是,相反的情况是真的。设计师会偏爱它在一个(松散)相关项目中发现的应用程序级别资源(即在一个依赖用户控件库作为其依赖项之一的项目中)。它将完全忽略你的用户控件库中的“DesignTimeResources.xaml”字典。只有当在整个解决方案中找不到其他资源候选项时,它才会使用“DesignTimeResources.xaml”。
  • 作为开发人员,你会面临另一个后果,即如果满足设计师用于选择其应用程序级别资源的标准的项目数量很多,你将会非常困惑。我的解决方案通常包含许多简单的测试工具。它们是小型启动项目,每个都有一个应用程序定义,其静态资源集并不一定完美。实际上,任何给定的测试工具通常都具有最差的应用程序级别资源示例之一,因为它的资源仅与完整应用程序的子集相关。但是,这些简单的测试工具通常是设计师在扫描解决方案以寻找其应用程序级别资源时要使用的那些工具;这可能导致非常意外的后果。同样,在各种测试工具之间切换当前启动项目时,它会显著影响和破坏设计师将使用的应用程序级别资源集。
为了解决这些实际问题,我通常会卸载设计师本来会找到的所有项目候选项。这迫使设计师依赖于用户控件库中本地的“DesignTimeResources.xaml”。或者,您可以卸载除当前用作启动项的单个项目之外的所有项目...但是请确保查看其资源,并且它们可在运行时在编辑控件时供设计师使用。
对我来说,WPF设计师(“xdesproc”)在整个解决方案中以杂乱无章和定义不清的方式进行搜索有点可怕。我怀疑我不是唯一一个因与应用程序资源相关的WPF设计师问题而遭受损失的人。我在互联网上没有找到很多关于设计师如何发现应用程序级别资源的信息。也许故意模棱两可,以便随着时间的推移更改行为。尽管我注意到最近有人报告了与“DesignTimeResources.xaml”相关的VS 2017错误,所以至少这不再是什么罕见的事情。
希望这些信息对于您遇到难以解释的设计师问题时有所帮助。如果您观察到与我在尝试VS 2017时不同的行为,请发表评论。

1
我有更多关于这个话题的答案(来自不是我自己的人)。这是来自微软工程师在Visual Studio开发者社区的观点...
请见链接:

https://developercommunity.visualstudio.com/content/problem/86265/xamlwpf-designer-will-not-find-application-resourc.html

我快速查看了我们寻找应用程序文档的逻辑。你在StackOverflow上的描述似乎很准确。我总结设计者的偏好顺序如下: 1.从包含打开XAML文件的项目中获取应用程序文档。 2.从启动项目获取应用程序文档。 3.从第一个引用包含打开XAML文件的项目的项目中获取应用程序文档。 没有设计师功能告诉用户我们选择了哪个应用程序文档。我们通常假设会使用#1或#2,并且大多数用户都希望如此。我可以理解,在复杂的解决方案中,遇到#3将导致不可预测的结果。

1
为了解决这种问题,我没有使用“DesignTimeResources.xaml”(我不知道那是什么)。
当我有包含控件的程序集需要在设计器中使用时,我会将App.xaml(以及App.xaml.cs)放在根目录下(例如从启动程序集中复制)。我将BuildAction设置为“Page”。
在App.xaml中,我引用预期在使用该程序集时加载的资源。
我们有一些级联程序集,因此每个包含控件的程序集都有一个“AllDictionaries.xaml”资源字典,可以被使用它的程序集引用。
以下是App.xaml内容示例:
<Application x:Class="RD.Controls.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/RD.Controls;component/AllDictionaries.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

将App.xaml文件放在程序集中可以确保加载“主字典”,该字典引用了来自引用程序集的任何其他所需资源。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接