将一个合并的词典添加到另一个合并的词典中

21
我似乎无法将合并的字典添加到XAML中合并字典的集合中。 Theme.xaml
<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="/Mine;component/Themes/Palette.Blue.xaml"/>
    <ResourceDictionary Source="/Mine;component/Themes/Template.xaml"/>
</ResourceDictionary.MergedDictionaries>

应用程序资源

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/Mine;component/Themes/Theme.xaml"/> 
            <!--
            <ResourceDictionary Source=="/Mine;component/Themes/Palette.Blue.xaml"/>
            <ResourceDictionary Source="/Mine;component/Themes/Template.xaml"/>
            -->
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

请注意:如果我将两个ResourceDictionaries都放在Appication.Resources MergedDictionary中(注释掉theme.xaml并取消其他两个字典的注释),它们都可以正确加载。但是,根据我们定义资源的方式,这可能意味着会加载相当多的资源,而且对于动态加载,我希望能够定义模板。


这是主题.xaml的完整代码吗?因为我认为你只需要用ResourceDictionary标签开始和结束它就可以工作了。 - dnr3
不,它实际上已经在一个合并的字典中了。只是似乎没有继承。 - The Real Baumann
3个回答

35

这是一个优化错误,请参见此链接

在XAML中创建每个对象时,如果存在默认样式(即具有Type键的样式),则应用该样式。正如您所想象的那样,有几种性能优化可以使该(隐含)查找尽可能轻量级。其中之一是,除非将其标记为“包含默认样式”,否则我们不会查看资源字典内部。存在一个错误:如果所有默认样式都嵌套在合并的字典中三层深度(或更深),则顶层字典不会被标记,因此搜索会跳过它。解决方法是在根字典中添加一个默认样式。

因此,在根字典中添加虚拟样式即可解决此问题。例如:

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/Mine;component/Themes/Theme.xaml"/>
        </ResourceDictionary.MergedDictionaries>
        <!-- Dummy Style, anything you won't use goes -->
        <Style TargetType="{x:Type Rectangle}" />
    </ResourceDictionary>
</Application.Resources>

我在.NET 4中遇到了这个确切的问题,这个解决方案解决了它。 - dex3703
4
由于某些原因,这对我不起作用。开始时,它会抛出一个异常(“Foreground”的DependencyProperty.UnsetValue无效),这表明资源字典未被添加。我的设置与上述.NET 4.5代码完全相同。 - erodewald
1
这在VS2010 .net 4.0中不起作用。这无法编译。错误Error 7 Property elements cannot be in the middle of an element's content. They must be before or after the content. - Franck
有人知道这个错误在.NET 4.5或更高版本中是否已修复吗?由于Microsoft Connect已经停用,因此我无法从提供的链接中得知。 - Joe

1

您的示例代码在App.xaml合并资源字典源中使用了双等号,用于Palette.Blue.xaml。我猜这只是您在此处发布示例时的笔误,而不是您真正遇到的问题。

在XAML中直接链接所有资源可能有些棘手。最简单的方法是从Blend的资源面板中完成。我创建了一个名为您示例的Silverlight应用程序,并在Blend中打开该项目,然后非常快速地将它们链接在一起。

App.xaml

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SilverlightApplication1.App">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Theme.xaml" />
                <!--
                <ResourceDictionary Source="Palette.Blue.xaml"/>
                <ResourceDictionary Source="Template.xaml"/>
                -->
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

Theme.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Palette.Blue.xaml"/>
        <ResourceDictionary Source="Template.xaml"/>
    </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

Template.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style TargetType="TextBox">
        <Setter Property="Margin" Value="10" />
        <Setter Property="Width" Value="250" />
    </Style>
    <Style x:Key="ReadOnlyTextBoxStyle" TargetType="TextBox">
        <Setter Property="IsReadOnly" Value="True" />
        <Setter Property="Foreground" Value="Black" />
        <Setter Property="IsTabStop" Value="False" />
        <Setter Property="Margin" Value="10" />
        <Setter Property="Width" Value="250" />
    </Style>
</ResourceDictionary>

Palette.Blue.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <SolidColorBrush x:Key="BlueSolidColorBrush" Color="SkyBlue" />
</ResourceDictionary>

MainPage.xaml

<UserControl x:Class="SilverlightApplication1.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel x:Name="LayoutRoot" Background="Honeydew">
        <TextBox Text="Read Only Textbox"
                 Style="{StaticResource ReadOnlyTextBoxStyle}" />
        <TextBox Text="Blue Textbox"
                 Background="{StaticResource BlueSolidColorBrush}" />
        <TextBox Text="Read Only, Blue Textbox"
                 Style="{StaticResource ReadOnlyTextBoxStyle}"
                 Background="{StaticResource BlueSolidColorBrush}" />
    </StackPanel>
</UserControl>

当然,如果您从不同的程序集中链接资源,那么它看起来会有所不同。事实上,在这种情况下,我建议您在代码后台合并您的字典。


1
那显然是一种转录错误(不在实际文件中)。我知道如何逐个添加每个资源(通过代码后台或创建新的MergedDictionary),但问题似乎与将MergedDictionary添加到ResourceDictionary中有关,无论是作为源还是作为单独合并字典的一部分。 - The Real Baumann
检查您的字典XAML文件的构建操作。您可能需要将其从默认页面更改为资源。 - Matt Casto

0

如果这是发生在你自己的控件上,我发现另一个解决方案是将DefaultStyleKey属性设置为null:

DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl), new FrameworkPropertyMetadata(null));

我不知道为什么这个有效,但它似乎是!


这个SO线程解释了OverrideMetadata的工作原理。 - Masius

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