XAML:如何更改特定ResourceDictionary的源代码

时间:2017-03-18 16:07:19

标签: c# wpf xaml uwp-xaml

<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>

如何根据ResourceDictionary ResourceDictionary.MergedDictionaries / ResourceDictionary更改x:Name内的x:Uid来源?

感谢。

1 个答案:

答案 0 :(得分:3)

我认为你不能基于x:Namex:Uid来做到这一点。 ResourceDictionary未定义这些标记属性的映射。例如,UIElement标有UidPropertyAttribute("Uid"),因此标有UIElement属性的x:Uid将该值作为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");