我试图在我正在使用的WPF应用中使用合并的ResourceDictionaries解决问题时遇到了这种奇怪的现象。
我在外部DLL(" common")中定义了自定义控件(TextButton,MenuButton)和资源(颜色,画笔,控件样式和自定义控件模板)。在另一个库中,我有一个使用这些样式的用户控件(" pluginA")。
只要我使用标准的WPF控件(TextBlock,Button,Grid等) - 我就可以应用" common" DLL没有任何问题。设计师会选择风格并正确应用它。
如果我将其中一个自定义控件(TextButton)放入" pluginA"中的用户控件中。 - 设计人员会找到自定义控件,但无法解析要应用的样式的类型(类型引用找不到名为' {clr-namespace:Common}的类型TEXT按钮'。)
我的usercontrol中的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的描述......任何人都可以解释为什么这会有效?
答案 0 :(得分:1)
pack:/Common;component/Resources/DefaultTheme/DefaultTheme.xaml
这在技术上是一个有效的URI,但它不是有效的pack
URI。根据{{1}}格式的规则解析它将产生:
包URI: pack
部分URI:<empty>
实际上,您通过附加/Common;component/Resources/DefaultTheme/DefaultTheme.xaml
方案从部件URI中创建了绝对URI。但是,如果没有格式良好的包组件,则结果不是有效的pack:
URI。而且,有趣的是,pack
类实际上不会将原始字符串解析为绝对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);
// ...
}
。那里的逻辑与WPF中的大多数BindUriHelper.GetResolvedUri(_baseUri, _source)
URI处理不同,它看到pack
不是绝对URI(至少根据损坏的_source
类),所以它尝试将它与已解析的基URI(我们假设为Uri
)相结合。 URI通过pack://application:,,,/
组合,这仅仅因为new Uri(Uri baseUri, Uri relativeUri)
错误地将原始字符串解析为相对URI而起作用。最终用于创建Uri
的URI等同于:
WebRequest
......产生:
new Uri(
new Uri("pack://application:,,,/"),
new Uri("pack:/Common;component/Resources/DefaultTheme/DefaultTheme.xaml"))
而且中提琴,我们最终从有效的包URI加载资源,即使我们给它一个无效的。
我们知道&#34;坏&#34; URI的工作原理是因为它意外地变成了一个好的。至于为什么那么好&#34;好&#34;当设备直接使用时,URI在设计器中不起作用,非常好奇。
也许您只需要重建pack://application:,,,/Common;component/Resources/DefaultTheme/DefaultTheme.xaml
项目和尝试合并资源字典的项目。如果它仍然失败,那么在设计器中运行时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>
查看设计器中显示的内容。它可能会给我们一个线索。