How to switch between light and dark mode in Material Design in XAML at runtime?

1.6k Views Asked by At

At runtime, I want to change my app's main theme (which in this case is the light theme) to the dark theme.

I'm using the C# programming language, with the WPF project template. And in this project.

I installed the MaterialDesignThemes library in my project, and by default I set it to the light theme.

<materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="DeepPurple" SecondaryColor="DeepOrange" />

Now I want to create a mechanism that can change the theme from light to dark at application runtime.

1

There are 1 best solutions below

1
SW Wanted On

We can divide this question into 2 occasions:

  • Using only Code-Behind
  • Using MVVM architecture

Using only Code-Behind

xaml:

<Window x:Class="GED.Views.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
    xmlns:local="clr-namespace:GED.Views"
    Title="MainWindow">
<Grid>
    <ToggleButton x:Name="DarkModeToggle"
                  Content="Dark Mode"
                  Checked="DarkModeToggle_Checked"/>
</Grid>

code-behind:

using MaterialDesignThemes.Wpf;
using System.Windows;

namespace GED.Views
{
    public partial class MainWindow : Window
    {
        public MainWindow ()
        {
            InitializeComponent();
        }

        private void DarkModeToggle_Checked(object sender, RoutedEventArgs e)
        {
            PaletteHelper palette = new PaletteHelper();

            ITheme theme = palette.GetTheme();

            if (DarkModeToggle.IsChecked.Value)
            {
                theme.SetBaseTheme(Theme.Dark);
            }
            else
            {
                theme.SetBaseTheme(Theme.Light);
            }
            palette.SetTheme(theme);
        }
    }
}

Using MVVM architecture

xaml:

<Window x:Class="GED.Views.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
    xmlns:local="clr-namespace:GED.Views" 
    xmlns:viewModel="clr-namespace:GED.ViewModels.Register"
    Title="MainWindow">

<Window.DataContext>
    <viewModel:MainViewModelStackoverFlow/>
</Window.DataContext>

<Grid>
    <ToggleButton x:Name="DarkModeToggle"
                  IsChecked="{Binding IsChecked}"
                  Command="{Binding DarkModeCommand}"
                  Checked="DarkModeToggle_Checked"/>
</Grid>

ViewModel:

using MaterialDesignThemes.Wpf;
using System.Windows.Input;

namespace GED.ViewModels
{
    public class MainViewModel : ViewModelBase
    {
        private bool _isChecked;

        public bool IsChecked
        {
            get { return _isChecked; }
            set
            {
                _isChecked = value;
                OnPropertyChanged(nameof(IsChecked));
            }
        }

        public ICommand DarkModeCommand { get; }

        public MainViewModelStackoverFlow()
        {
            DarkModeCommand = new ViewModelCommand(ExecuteDarkModeCommand);
        }

        private void ExecuteDarkModeCommand(object obj)
        {
            PaletteHelper palette = new PaletteHelper();

            ITheme theme = palette.GetTheme();

            if (IsChecked)
            {
                theme.SetBaseTheme(Theme.Dark);
            }
            else
            {
                theme.SetBaseTheme(Theme.Light);
            }
            palette.SetTheme(theme);
        }
    }
}

Note

You may have noticed that the MainViewModel is being inherited by the class called ViewModelBase, and also in the constructor of the class, an instance was created with the ViewModelCommand class.

For you to understand what these classes are, you need to know how to implement the MVVM architecture in your project.

In general it can be said that:

ViewModelBase

  • is a class inherited by all ViewModel that intend to implement the INotifyPropertyChanged interface, and this generates a event void OnPropertyChange(string property); which is responsible for notifying each change that is made to a property in the front-end (View).

ViewModelCommand

  • also known as RelayCommand is the class that handles each event in a generic way. When it comes to an event, in the remaining ViewModels, a ReadOnly property of type ICommand is used to serve as a trigger in View controls, as in the case of <ToggleButton/>.