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

时间:2016-01-01 09:05:45

标签: c# windows-10 windows-10-mobile windows-10-universal

我可以使用this.RequestedTheme = ElementTheme.Dark;更改主题 但我需要的是整个应用程序级别,因为这只会将当前页面的主题更改为黑暗。

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

  

UWPApp.exe中出现“System.NotSupportedException”类型的异常,但未在用户代码中处理

有没有这样的方法可以将整个应用程序主题从Light变为Dark,反之亦然?

我正在使用VS2015

4 个答案:

答案 0 :(得分:15)

根据我最终决定的内容更新了答案。

我使用了一个设置类,其中包含所有应用设置,包括要使用的主题。由于主题只能在启动时设置,我们需要确保将它们设置为主题。这是我使用的代码:

在App.xaml.cs文件中:

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

    this.InitializeComponent();
}

在App.xaml文件中,请务必删除此属性:

    RequestedTheme="Light"

如果没有删除它,它总是默认为亮,无法改变它。

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

答案 1 :(得分:9)

应用程序的RequestedTheme只能在构造函数中更新。但是(如您所发现的),Page的RequestedTheme可以在运行时随时更新。

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

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

  

主题只能在应用程序启动时设置,而不能在运行时设置。在应用程序运行时尝试设置RequestedTheme会引发异常(Microsoft .NET代码的NotSupportedException)。如果您为用户提供选择属于应用程序UI的主题的选项,则必须将该设置保存在应用程序数据中,并在重新启动应用程序时应用该设置。

应该有解决方法,但它们会非常愚蠢.Microsoft在他们自己的官方应用程序中执行此操作,例如Groove ...

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

  1. 创建您自己的BasePage(继承自Page)
  2. 将您的设置保留在静态类下,并创建一个事件以跟踪模型更改。
  3. 在你的BasePage的构造函数中,听取这个事件并在有的时候应用更改。
  4. 我现在无法提供代码示例(因为我今天很忙),但这是迄今为止恕我直言最有效的方式。

答案 2 :(得分:3)

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

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

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

答案 3 :(得分:0)

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

首先,我创建了一个带有Theme属性的设置类,该属性会自动存储当前设置:

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

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

  public MainPage()
  {
     this.InitializeComponent();

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

这将根据应用程序内存中的上一个设置来设置主题,并将切换开关设置为匹配。

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

  /// <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;
  }

这可以处理切换开关的切换:

  /// <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开关创建以上所有代码:

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

此设置非常简单,希望可以省去一些麻烦的工作。