Изменение темы в Windows 10 UWP App Programmatically

Мне удалось изменить тему, используя this.RequestedTheme = ElementTheme.Dark; Но мне нужен весь уровень приложения, так как он только меняет тему текущей страницы на темноту.

Всякий раз, когда я пытаюсь выполнить этот App.Current.RequestedTheme = ApplicationTheme.Dark; Я всегда получаю эту ошибку

Исключение типа "System.NotSupportedException" произошло в UWPApp.exe, но не было обработано в коде пользователя

Есть ли способ изменить всю тему приложения от Light to Dark или наоборот?

Я использую VS2015

Ответ 1

Обновленный ответ с тем, что я наконец решил.

Я использовал класс настроек, который содержит все настройки приложений, включая тему, которую нужно использовать. Поскольку тема может быть задана только при ее запуске, нам необходимо убедиться в ее установке. Это код, который я использовал:

В файле App.xaml.cs:

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

    this.InitializeComponent();
}

В файле App.xaml убедитесь, что удалить это свойство:

    RequestedTheme="Light"

Если его не удалять, он всегда по умолчанию загорается, не изменяя его.

Таким образом, пользователь может выбрать тему, она будет храниться и использоваться при запуске приложения. Просто загрузите его и примените в фазе инициализации приложения.

Ответ 2

Application RequestedTheme может обновляться только в конструкторе. Однако (как вы обнаружили) страница RequestedTheme может быть обновлена ​​в любое время во время выполнения.

Это действительно раздражает, я знаю, и не так много информации об этой ситуации, кроме этой страницы MSDN:

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

Тема может быть установлена ​​только при запуске приложения, а не во время его запуска. Попытка установить RequestedTheme во время запуска приложения вызывает исключение (NotSupportedException для кода Microsoft.NET). Если вы дадите пользователю возможность выбрать тему, которая является частью пользовательского интерфейса приложения, вы должны сохранить этот параметр в данных приложения и применить его при перезапуске приложения.

Должны быть обходные пути, но они будут очень тупыми. Microsoft делает это в своих официальных приложениях, таких как Groove, хотя...

Мое решение выполняет обновление темы на уровне элемента, а не на уровне приложения.

  • Создайте свой собственный BasePage (унаследованный от страницы)
  • Сохраняйте свои настройки под статическим классом и создайте событие, чтобы отслеживать изменения модели.
  • В своем конструкторе BasePage прослушивайте это событие и применяйте изменения, когда есть.

Я не могу представить пример кода прямо сейчас (так как я очень занят сегодня), но это, безусловно, самый эффективный способ ИМХО.

Ответ 3

Я нашел другое решение, которое мне очень помогло. Если у приложения есть корневой фрейм, который загружает страницы (что имеет место по умолчанию), я мог бы установить для запрошенной темы этого корневого фрейма желаемое значение, и тема приложения была изменена без перезапуска. Код выглядит так:

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

Я получил этот фрагмент из репозитория Windows Template Studio GitHub здесь, так что, похоже, это лучший способ сделать это.

Ответ 4

Я считаю, что ответ 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 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" />

Эта настройка достаточно проста и, возможно, может спасти кого-то от тяжелой работы.