Search code examples
c#wpfthemesresourcedictionarymergeddictionaries

Why still can't find the resource after I add it into ResourceDictionary?


I want to achieve themes in my WPF program.

I stored the color in the database and then load it into MergedDictionaries.

Here are my codes:

<Application x:Class="Test"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Test"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary>
                    <ResourceDictionary.MergedDictionaries>
                    </ResourceDictionary.MergedDictionaries>
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>            
        </ResourceDictionary>
    </Application.Resources>
</Application>

And here are code-behind:

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.IO;
using System.Linq;
using System.Resources;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Resources;

namespace Test
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        public App()
        {
            ChangeTheme("Dark");
        }
        public ResourceDictionary ThemeDictionary
        {
            get { return Resources.MergedDictionaries[0]; }
        }
       
        public void ChangeTheme(string ThemeName)
        {
            Resources.MergedDictionaries.Clear();
            Resources.MergedDictionaries.Add(new ResourceDictionary());
            ///some logic to load color from database
            ThemeDictionary.Add("NormalBackground",new SolidColorBrush(Colors.Red));            
        }
    }
}

And here are sample of front-end:

<Window x:Class="Test"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Test"
        mc:Ignorable="d"
        Height="450" Width="800">
    <Grid Background="{StaticResource NormalBackground}">
        
    </Grid>
</Window>

After the program ran. VS reports error that cannot find StaticResource "NormalBackground".

Whereas, if I add an exist ResourceDictionary into the MergedDictionaries, all works well.

What's wrong with my code? Thank you.


Solution

  • You are calling "ChangeTheme("Dark")" too early. It should be called from within OnStartup in App.xaml.cs. I guess that the resource dictionaries defined in the xaml (which is empty in your case) will overwrite everything you put in there by code in your constructor.

    public App()
    {
      
    }
    
    protected override void OnStartup(StartupEventArgs e)
    {
      base.OnStartup(e);
    
      ChangeTheme("Dark");
    }
    

    Also, you can remove the inner part of your MergedDictionaries from you App.xaml

    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>