XAML: 如何更改特定 ResourceDictionary 的来源

XAML: How can I change the source of a specific ResourceDictionary

<Application x:Class="CDesign.App"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:local="clr-namespace:CDesign"
         StartupUri="MainWindow.xaml">
<Application.Resources>
    <ResourceDictionary x:Name="ThemeDictionary">
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/AppStyles;component/Resources/Icons.xaml"/>
            <ResourceDictionary Source="pack://application:,,,/AppStyles;component/Resources/IconsNonShared.xaml"/>
            <!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->
            <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
            <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
            <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
            <!-- Accent and AppTheme setting -->
            <ResourceDictionary x:Uid="Accents" x:Name="Accents" Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
            <ResourceDictionary x:Uid="BaseTheme" x:Name="BaseTheme" Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

如何根据 ResourceDictionaryx:Name/x:Uid 更改 ResourceDictionary.MergedDictionaries 中特定 ResourceDictionary 的来源?

谢谢。

我认为您无法根据 x:Namex:Uid 做到这一点。 ResourceDictionary 没有为这些标记属性定义映射。例如,UIElement 标记为 UidPropertyAttribute("Uid"),因此标记为 x:Uid 属性的 UIElement 将具有可用的值 Uid 属性。 x:Name 同样的故事。但是 ResourceDictionary 没有定义这样的映射,所以这些属性在 xaml 被解析和编译后实际上丢失了。

现在,您可以做什么呢?想到的一个选项是使用您自己的附加 属性 为资源字典分配一个标识符。不幸的是,ResourceDictionary 没有继承自 DependencyObject,因此我们不能在其上使用附加属性。

然而,有一种技巧可以让我们滥用附加的 属性 语法并仍然达到目标。让我们像这样定义假附加 属性:

public static class ResourceDictionaryExtensions {   
    private static readonly Dictionary<ResourceDictionary, string> _mapping = new Dictionary<ResourceDictionary, string>();
    public static void SetName(ResourceDictionary element, string value) {
        _mapping[element] = value;
    }

    public static string GetName(ResourceDictionary element) {
        if (!_mapping.ContainsKey(element))
            return null;
        return _mapping[element];
    }
}

请注意,此定义不同于通常附加的 属性。首先,根本没有附加 属性。其次,GetNameSetName 这两个方法不接受 DependencyObject(就像与附加属性关联的方法一样),但是 ResourceDictionary。但是,因为我们有 GetNameSetName 方法 - 我们可以使用附加的 属性 语法,如下所示:

<Application.Resources>
    <ResourceDictionary x:Name="ThemeDictionary">
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/AppStyles;component/Resources/Icons.xaml"/>
            <ResourceDictionary Source="pack://application:,,,/AppStyles;component/Resources/IconsNonShared.xaml"/>
            <!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->
            <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
            <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
            <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
            <!-- Accent and AppTheme setting -->
            <ResourceDictionary local:ResourceDictionaryExtensions.Name="Accents" Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
            <ResourceDictionary local:ResourceDictionaryExtensions.Name="BaseTheme" Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

即使目标对象 (ResourceDictionary) 不是依赖对象,而且 属性 根本没有附加 属性。

现在很容易修改目标字典的来源:

var dict = Application.Current.Resources.MergedDictionaries.First(c => ResourceDictionaryExtensions.GetName(c) == "Accents");
dict.Source = new Uri("path to the new dictionary");