【问题标题】:WPF pack:/[assemblyName];component/... vs pack://application:,,,/[assemblyName];component/...?WPF pack:/[assemblyName];component/... vs pack://application:,,,/[assemblyName];component/...?
【发布时间】:2014-11-20 17:29:56
【问题描述】:

我在尝试在我正在开发的 WPF 应用程序中使用合并的 ResourceDictionaries 解决问题时遇到了这个奇怪的问题。

我在外部 DLL(“通用”)中定义了自定义控件(TextButton、MenuButton)和资源(颜色、画笔、控件样式和自定义控件模板)。在另一个库中,我有一个使用这些样式的用户控件(“pluginA”)。

只要我使用标准 WPF 控件(TextBlock、Button、Grid 等),我就可以毫无问题地应用“通用”dll 中的样式。设计师会选择风格并正确应用。

如果我将其中一个自定义控件 (TextButton) 放入“pluginA”中的用户控件中 - 设计人员会找到 自定义控件,但无法将样式的类型解析为被应用(类型引用找不到名为 '{clr-namespace:Common}TextButton' 的类型)。

我的用户控件中的 xmlns 声明如下所示:

<UserControl x:Class="PluginA.Views.LeftBarView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:core="clr-namespace:Common.Core;assembly=Common"
             xmlns:common="clr-namespace:Common;assembly=Common"
             mc:Ignorable="d" 
             d:DesignHeight="600" d:DesignWidth="300">
<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <core:SharedResourceDictionary Source="/Common;component/Resources/DefaultTheme/DefaultTheme.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</UserControl.Resources>

使用此定义,设计器不会应用任何样式 - 但它可以在运行时工作。很好,但不是很有帮助,因为我不想运行应用程序来查看小调整是否生效。

所以我尝试了这个:

<core:SharedResourceDictionary Source="pack://application:,,,/Common;component/Resources/DefaultTheme/DefaultTheme.xaml" />

但这并没有改变任何东西(设计师仍然找不到资源)。在更改代码的过程中,我得到了这个:

<core:SharedResourceDictionary Source="pack:/Common;component/Resources/DefaultTheme/DefaultTheme.xaml" />

现在设计者很高兴并且可以找到资源 - 运行时很高兴并显示资源,但我找不到任何关于这是有效 PACK URI 的描述......谁能解释为什么这会起作用?

【问题讨论】:

  • 您是否尝试在拥有有效的包 uri 时进行重建?
  • 对不起 - 被拖到其他事情上了。明天我上班的时候试试看。
  • 我把它改回了一个有效的包 URI,效果很好。从那时到现在,我确实将更新 4 安装到 VS2013,也许有一些问题得到修复,导致它再次按预期工作......?谢谢你的帮助!! :D

标签: wpf xaml resourcedictionary


【解决方案1】:

pack:/Common;component/Resources/DefaultTheme/DefaultTheme.xaml

这在技术上是一个有效的 URI,但它不是一个有效的 pack URI。根据pack 格式的规则解析它会产生:

包 URI:&lt;empty&gt;
部分 URI:/Common;component/Resources/DefaultTheme/DefaultTheme.xaml

实际上,您通过附加 pack: 方案从部分 URI 中创建了一个绝对 URI。但是,如果没有格式良好的包组件,则结果不是有效的pack URI。而且,有趣的是,Uri 类实际上不会将原始字符串解析为绝对 URI。它被错误地解析为相对 URI,这也是它在分配给 ResourceDictionary.Source 时起作用的部分原因。我们来看看属性设置器:

public Uri Source
{
    get { return _source; }
    set
    {
        // ...
        _source = value;

        Clear();

        Uri uri = BindUriHelper.GetResolvedUri(_baseUri, _source);
        WebRequest request = WpfWebRequestHelper.CreateRequest(uri);
        // ...
}

关键在于BindUriHelper.GetResolvedUri(_baseUri, _source)。那里的逻辑与 WPF 中的大部分 pack URI 处理不同,它看到 _source 不是绝对 URI(至少根据损坏的 Uri 类),因此它尝试将其与已解析的基本 URI,我们假设它是pack://application:,,,/。 URI 是通过new Uri(Uri baseUri, Uri relativeUri) 组合的,这只是因为Uri 错误地将原始字符串解析为相对URI。最终用于创建WebRequest 的 URI 相当于:

new Uri(
    new Uri("pack://application:,,,/"),
    new Uri("pack:/Common;component/Resources/DefaultTheme/DefaultTheme.xaml"))

...产生:

pack://application:,,,/Common;component/Resources/DefaultTheme/DefaultTheme.xaml

而且 viola,我们最终会从一个有效的包 URI 加载资源,即使我们给了它一个无效的资源。

我们知道“坏”的 URI 可以正常工作,因为它会意外地转换为好的 URI。至于为什么直接使用相同的“好”URI 在设计器中不起作用,这很好奇。

也许您只需要重建Common 项目和试图合并资源字典的项目。如果它仍然失败,那么您的UserControl.Resources 在设计器中运行时的BaseUri 可能与在运行时不同。让我们看看我们是否可以在设计时弄清楚BaseUri 是什么。修改你的UserControl如下:

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             ...
             xmlns:m="clr-namespace:System.Windows.Markup;assembly=System.Xaml"
             x:Name="Root">
  <UserControl.Resources>
    <ResourceDictionary">
      <Style x:Key="BaseUriTextStyle" TargetType="TextBlock">
        <Setter Property="Text"
                Value="{Binding ElementName=Root,
                                Path=Resources.(m:IUriContext.BaseUri)}" />
      </Style>
    </ResourceDictionary>
  </UserControl.Resources>

  <TextBlock Style="{StaticResource BaseUriTextStyle}" />
</UserControl>

查看设计器中显示的内容。它可能会给我们一个线索。

【讨论】:

    猜你喜欢
    • 2011-11-21
    • 1970-01-01
    • 2021-09-17
    • 1970-01-01
    • 2011-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多