Home > front end >  Why still can't find the resource after I add it into ResourceDictionary?
Why still can't find the resource after I add it into ResourceDictionary?

Time:01-03

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.

CodePudding user response:

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>

CodePudding user response:

According to the logic of work in the current implementation, you first set your dictionary in the App constructor. After that, the XAML is initialized. Upon XAML initialization, the <ResourceDictionary> tag creates a new dictionary and stores it in App.Resources. This action removes the instance you created in the constructor. Therefore, when the UserControl is called, the App only has an empty dictionary in which your resource does not exist.

For your implementation to work properly, you should remove the <Application.Resources> section entirely from the XAML.

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

As others have suggested, replacing StaticResource with DynamicResource is not a solution, as there is no resource itself with the specified key. DynamicResource can help if you replace the resource pointed to by DynamicResource or the dictionary with this resource at runtime.

  • Related