以编程方式更改 Windows 10 UWP App 中的主题

Changing Theme in Windows 10 UWP App Programmatically

我可以使用 this.RequestedTheme = ElementTheme.Dark; 更改主题 但是我需要的是整个应用层,因为这个只是把当前页面的主题改成深色。

每当我尝试这个时 App.Current.RequestedTheme = ApplicationTheme.Dark; 我总是收到这个错误

An exception of type 'System.NotSupportedException' occurred in UWPApp.exe but was not handled in user code

有没有一种方法可以将整个应用程序主题从浅色更改为深色,反之亦然?

我正在使用 VS2015

更新了我最终决定的答案。

我使用了一个设置 class 来保存所有应用程序设置,包括要使用的主题。由于主题只能在启动时设置,我们需要确保设置它们。这是我使用的代码:

在 App.xaml.cs 文件中:

public App()
{
    //Load settings
    AppSettings.LoadSettings();
    this.RequestedTheme = AppSettings.SelectedTheme;

    this.InitializeComponent();
}

在 App.xaml 文件中确保 删除 这个 属性:

    RequestedTheme="Light"

如果不删除它,它始终默认为亮起,无法更改。

这样用户可以选择主题,它会在应用启动时被存储和使用。只需确保在应用程序初始化阶段加载并应用它即可。

应用程序的 RequestedTheme 只能在 constructor.However 中更新(如您所见),页面的 RequestedTheme 可以在运行时随时更新。

我知道这真的很烦人,除了这个 MSDN 页面之外,没有太多关于这种情况的信息:

https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.application.requestedtheme?f=255&MSPPError=-2147217396

The theme can only be set when the app is started, not while it’s running. Attempting to set RequestedTheme while the app is running throws an exception (NotSupportedException for Microsoft .NET code). If you give the user an option to pick a theme that's part of app UI, you must save the setting in the app data and apply it when the app is restarted.

应该有变通办法,但他们会非常 dumb.Microsoft 在他们自己的官方应用程序(如 Groove)中这样做...

我的解决方案是在元素级别而不是应用程序级别进行主题更新。

  1. 创建自己的 BasePage(继承自 Page)
  2. 将您的设置保持在静态 class 并创建一个事件以继续跟踪模型更改。
  3. 在您的 BasePage 的构造函数中监听此事件并在发生时应用更改。

我现在无法提供代码示例(因为我今天很忙),但恕我直言,这是迄今为止最有效的方式。

我找到了另一个对我来说效果很好的解决方案。如果应用程序有一个加载页面的根框架(默认情况下就是这种情况),我可以将该根框架的请求主题设置为所需的值,并且应用程序的主题已更改而无需重新启动。代码如下所示:

// Set theme for window root.
if (Window.Current.Content is FrameworkElement frameworkElement)
{
   frameworkElement.RequestedTheme = theme;
}

我从 Windows Template Studio GitHub 存储库 here 中获得了该片段,因此这似乎是执行此操作的最佳方式。

我发现 axnull 的回答最有帮助,因为它允许在应用 运行 时设置主题。经过一个多下午的工作,我能够即时设置应用程序的主题并将其保存在内存中以供下次启动,让用户通过 ToggleButton.

进行控制

首先,我用 Theme 属性 进行了设置 class,它会自动存储当前设置:

AppSettings.cs

class AppSettings
{
   public const ElementTheme DEFAULTTHEME = ElementTheme.Light;
   public const ElementTheme NONDEFLTHEME = ElementTheme.Dark;

   const string KEY_THEME = "appColourMode";
   static ApplicationDataContainer LOCALSETTINGS = ApplicationData.Current.LocalSettings;

   /// <summary>
   /// Gets or sets the current app colour setting from memory (light or dark mode).
   /// </summary>
   public static ElementTheme Theme {
      get {
         // Never set: default theme
         if (LOCALSETTINGS.Values[KEY_THEME] == null)
         {
            LOCALSETTINGS.Values[KEY_THEME] = (int)DEFAULTTHEME;
            return DEFAULTTHEME;
         }
         // Previously set to default theme
         else if ((int)LOCALSETTINGS.Values[KEY_THEME] == (int)DEFAULTTHEME)
            return DEFAULTTHEME;
         // Previously set to non-default theme
         else
            return NONDEFLTHEME;
      }
      set {
         // Error check
         if (value == ElementTheme.Default)
            throw new System.Exception("Only set the theme to light or dark mode!");
         // Never set
         else if (LOCALSETTINGS.Values[KEY_THEME] == null)
            LOCALSETTINGS.Values[KEY_THEME] = (int)value;
         // No change
         else if ((int)value == (int)LOCALSETTINGS.Values[KEY_THEME])
            return;
         // Change
         else
            LOCALSETTINGS.Values[KEY_THEME] = (int)value;
      }
   }
}

然后,在页面构造函数中,添加如下代码:

MainPage.xaml.cs

  public MainPage()
  {
     this.InitializeComponent();

     // Set theme for window root
     FrameworkElement root = (FrameworkElement)Window.Current.Content;
     root.RequestedTheme = AppSettings.Theme;
     SetThemeToggle(AppSettings.Theme);
  }

这会根据之前在应用程序内存中的选择设置主题,并设置切换以匹配。

页面加载时调用以下方法:

MainPage.xaml.cs

  /// <summary>
  /// Set the theme toggle to the correct position (off for the default theme, and on for the non-default).
  /// </summary>
  private void SetThemeToggle(ElementTheme theme)
  {
     if (theme == AppSettings.DEFAULTTHEME)
        tglAppTheme.IsOn = false;
     else
        tglAppTheme.IsOn = true;
  }

这会处理开关的切换:

MainPage.xaml.cs

  /// <summary>
  /// Switch the app's theme between light mode and dark mode, and save that setting.
  /// </summary>
  private void ToggleSwitch_Toggled(object sender, RoutedEventArgs e)
  {
     FrameworkElement window = (FrameworkElement)Window.Current.Content;

     if (((ToggleSwitch)sender).IsOn)
     {
        AppSettings.Theme = AppSettings.NONDEFLTHEME;
        window.RequestedTheme = AppSettings.NONDEFLTHEME;
     }
     else
     {
        AppSettings.Theme = AppSettings.DEFAULTTHEME;
        window.RequestedTheme = AppSettings.DEFAULTTHEME;
     }
  }

正在为以下 ToggleButton 开关创建以上所有代码:

MainPage.xaml

<ToggleSwitch Name="tglAppTheme"
              Header="Theme"
              OffContent="Light"
              OnContent="Dark"
              IsOn="False"
              Toggled="ToggleSwitch_Toggled" />

此设置非常简单,有望为某些人省去繁重的工作。