Xamarin 以编程方式交换单个 ResourceDictionary

Xamarin swap single ResourceDictionary programmatically

我目前正在尝试让自定义主题与 Xamarin 应用程序一起使用,并且我找到了一种方法可以按照我想要的方式进行这项工作,但它似乎非常低效,所以我想我会问看看你们有没有更好的答案。

所以问题来了,我想构建一个用户可以更改主题的屏幕(会有很多,不仅仅是 light/dark),我想换出当前主题 ResourceDictionary 并将其替换为新选择的主题的 ResourceDictionary。问题是我还希望该应用程序具有其他全局 ResourceDictionaries,我发现的每个教程都建议调用 Resources.MergedDictionaries.Clear(),但那样会摆脱我的其他 ResourceDictionaries。

这是我的Xaml,我不想替换DefaultButton.xaml或LinkButton.xaml,我只想替换LightTheme.xaml。

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="myTestApp.App">
    <Application.Resources>
        <ResourceDictionary Source="Themes/ResourceDictionaries/LightTheme.xaml" />
        <ResourceDictionary Source="Styles/DefaultButton.xaml" />
        <ResourceDictionary Source="Styles/LinkButton.xaml" />
    </Application.Resources>
</Application>

然后在我的应用程序中class我有

public void ChangeTheme(ThemeOptions theme)
{
    ResourceDictionary newRes;
    switch (theme)
    {
        case ThemeOptions.Light:
            newRes = new LightTheme();
            break;
        case ThemeOptions.Dark:
            newRes = new DarkTheme();
            break;
        default:
            newRes = new LightTheme();
            break;
    }
    
    Resources.MergedDictionaries.Clear();
    Resources.Add(newRes);
}

显然 DefaultButton.xaml 和 LinkButton.xaml ResourceDictionaries 现在已经被清除了。我可以将它们添加回去,但仅查找和删除主题似乎效率非常低。有没有简单的方法来简单地识别我想要覆盖和替换的 ResourceDictionary?

我相信我可能找到了问题的答案,但没有找到原始问题的答案。我创建了一个“BundledSiteStyles”ResourceDictionary,并将其作为 MergedDictionary 添加到我的每个主题中。然后 App.xaml 文件只加载一个主题,所有样式都随之而来。

所以我的 App.xaml 没有添加 ResourceDictionaries,然后在启动时以编程方式获得活动主题并调用我的 ChangeTheme 函数

public void ChangeTheme(ThemeOptions theme)
{
    switch (theme)
    {
        case ThemeOptions.Light:
            Resources = new LightTheme();
            break;
        case ThemeOptions.Dark:
            Resources = new DarkTheme();
            break;
        default:
            Resources = new LightTheme();
            break;
    }
}

这是我的 LightTheme.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    x:Class="myTestApp.Themes.ResourceDictionaries.LightTheme">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="../../Styles/BundledSiteStyles.xaml" />
    </ResourceDictionary.MergedDictionaries>
    <Color x:Key="LinkButtonBackgroundColor">Transparent</Color>
    <Color x:Key="LinkButtonTextColor">Blue</Color>
    <!-- Add more colours here -->
</ResourceDictionary>  

这是我的 BundledSiteStyles.xaml

<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    x:Class="myTestApp.Styles.BundledSiteStyles">
    <ResourceDictionary.MergedDictionaries>
        <!-- Add global ResourceDictionaries Here -->
        <ResourceDictionary Source="DefaultButton.xaml" />
        <ResourceDictionary Source="LinkButton.xaml" />
    </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

如果有更 efficient/correct 的方法,请告诉我,但目前看来可行。

假设所有主题都有相同的键,您可以通过遍历它的键来替换它,并替换合并字典中的那些条目。

我没有测试过,但应该是这样的:

var resources = Application.Current.Resources;

foreach (var key in themes.Keys)
    resources[key] = themes[key];