【问题标题】:XAML designer with UserControls in DLL doesn't resolve resourceDLL 中带有 UserControls 的 XAML 设计器无法解析资源
【发布时间】:2021-02-21 21:29:09
【问题描述】:

我在 Visual Studio 2019 中有一个解决方案,由一些使用 WPF .NET 5 构建为 DLL 的项目组成。

现在我需要在其中一个项目中创建一些 UserControls,我将在未来的 WPF .NET 5 应用程序中加载它们,但问题是 XAML 设计器无法使用 @ 预览 UserControl 987654323@ 在外部ResourceDictionary 中。

我简化了代码:

    <UserControl.Resources>
            <Style x:Key="sButton" TargetType="Button">
                <Setter Property="BorderBrush" Value="{StaticResource color_UC_BorderBrush}"/>
            </Style>
    </UserControl.Resources>

只有 DLL 我没有 Application 与共享的 ResourceDictionarycolor_UC_BorderBrush 无法解析以供预览。

通过以下方式,XAML 设计器可以正常工作,但我不希望每个 UserControl 每次都加载自己的 ResourceDictionary

    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/MyLib;component/ResourceDictionaries/myRD.xaml"/>
            </ResourceDictionary.MergedDictionaries>
            <Style x:Key="sButton" TargetType="Button">
                <Setter Property="BorderBrush" Value="{StaticResource color_UC_BorderBrush}"/>
            </Style>
        </ResourceDictionary>
    </UserControl.Resources>

在我未来的 WPF .NET 5 应用程序中,我将使用共享的 ResourceDictionary,但现在 我怎样才能设法让 XAML 设计器在 DLL 中正常工作,或者我怎样才能使 MergedDictionary 在XAML 可忽略?

也许还有其他我没有想到的方法。谢谢。

【问题讨论】:

  • 我没有针对您的特定用例的解决方案。因为这对我来说似乎不是问题。 UserControl 库不应该有自己的默认视觉属性吗?为客户端代码提供一种机制来覆盖这些属性似乎很好,但是为什么要强制它们呢?为所有内容提供默认值将简化您的生活(因为上述问题消失了)以及客户端代码作者的生活(因为他们只需要在关心它们时提供可视属性)。
  • @PeterDuniho “默认值”是什么意思?现在我在考虑StaticResource color_UC_BorderBrush作为默认值,所以如果我想改变多个控件的多个属性的值我可以简单地编辑资源值,是不是错了?
  • 我的意思是您的设计似乎需要 客户端 为画笔提供值,即使客户端代码并不关心使用什么颜色。将此与除您自己的代码之外的库发布的所有其他 UI 元素进行对比,其中如果需要某种颜色,则无需您额外努力即可提供默认颜色。 TextBlock 是否要求您提供前景画笔? Button 是否要求您提供背景、边框、焦点高亮等画笔?不,他们没有。如果您愿意,您可以取代它们,但您没有必须这样做。

标签: wpf xaml visual-studio-2019 .net-5


【解决方案1】:

您不能省略将资源合并到依赖它的控件范围内的ResourceDictionary

但不是将相同的资源合并到每个控件的ResourceDictionary 中,您可以选择一个共同父级的ResourceDictionary。 XAML 资源查找策略将遍历逻辑树以搜索所需资源,从控件的本地 ResourceDictionary 开始,到根目录结束,然后检查 App.xamlGeneric .xaml.

如果是UserControl,则必须使用DynamicResource 标记扩展。这是因为内容在运行时只是逻辑树的一部分。在设计时,从用户控件内容的角度来看,根是包含UserControl

您应该知道DynamicResource 有性能损失。所以你通常会尽量避免它。
在每个控件的 ResourceDictionary 中定义资源也会导致性能损失。
最好的解决方案是在应用程序的根控件中定义资源,例如 Window.Resources,或者在 App.xaml 中的 ResourceDictionary 中定义更好。
使用 App.xaml 来托管合并的 ResourceDictionary 还允许使用更便宜的 StaticResourceUserControl 内部查找合并的资源。

请阅读Static and dynamic resources 了解有关 XAML 引擎查找行为的更多信息。

以下示例选择MainWindow 作为合并资源的主机。它是它所包含的所有元素的根,因此可以从其逻辑树中的任何位置访问。

MainWindow.xaml
使资源可用于MainWindow 的任何子元素:

<Window>
  <Window.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>

        <!-- The resource dictionary that contains the shared 'color_UC_BorderBrush' resource -->
        <ResourceDictionary Source="pack://application:,,,/MyLib;component/ResourceDictionaries/myRD.xaml" />
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Window.Resources>

  <MyUserControl />
</Window>

MyUserControl.xaml

<UserControl>
  <UserControl.Resources>
    <Style x:Key="sButton" TargetType="Button">
      <Setter Property="BorderBrush" 
              Value="{DynamicResource color_UC_BorderBrush}" />
    </Style>
  </UserControl.Resources>

  <Button Style="{StaticResource sButton}" />
</UserControl>

【讨论】:

  • 仅使用DynamicResource color_UC_BorderBrush 不会出现错误,但 XAML 设计器并不能正确加载每个资源。
  • 通过测试应用程序,我可以使用 App.xaml,但无论如何设计器不会显示控件及其与资源相关联的属性。它只在运行时工作,但我想要的是继续使用StaticResource,而不是使用测试应用程序并在设计器中显示 XAML,因为它应该在运行时,在 DLL 项目中。
  • 您必须构建应用程序。之后,设计师应该给你一个预览。这肯定有效。如果你想坚持使用 StaticResource,你必须满足一些要求。你显然不能。因此,您只剩下 DynamicResource - 它还将为您提供 XAML 设计器预览。
  • 您应该有一个带有 MainWindow 的应用程序程序集。当您在此处使用控件时,您将获得预览。
  • 或者继续将资源合并到用户控件的ResourceDictionary。这是您的选择。
猜你喜欢
  • 2014-02-24
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 2019-03-06
  • 1970-01-01
  • 1970-01-01
  • 2015-04-30
相关资源
最近更新 更多