Modify WPF resource at runtime, where resource is defined in a resource dictionary of shared dll

931 views Asked by At

My WPF project references another project. In the referenced project, I have some colors and brushes defined in it.

Shared dll's resources:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    <Color x:Key="FooColor">#FF00FF00</Color>
    <SolidColorBrush x:Key="FooColorBrush" Color="{DynamicResource FooColor}" />
</ResourceDictionary>

Main project's App.xaml:

<Application x:Class="MyProject.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             ShutdownMode="OnExplicitShutdown">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Shared;component/UI/Resources.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

How can I modify the colors/brushes of the shared dll's resources at runtime?

In my App.xaml.cs, I tried:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        //base.OnStartup(e)
        
        // Didn't work - tried modifying the color from this.Resources
        this.Resources.Remove("FooColor");
        this.Resources.Add("FooColor", Color.FromArgb(255, 255, 255, 0));

        // Didn't work - tried modifying the color from the Merged Dictionary
        ResourceDictionary sharedResources = this.Resources.MergedDictionaries.First(x => x.Source.OriginalString.Contains("/Shared;component/UI/Resources.xaml"));
        sharedResources.Remove("FooColor");
        sharedResources.Add("FooColor", Color.FromArgb(255, 255, 255, 0));
    }
}

If the resource that I'm trying to modify is defined in the current project's App.xaml, then this works just fine:

this.Resources.Remove(resourceKey);
this.Resources.Add(resourceKey, newValue);

To test it, in my MainWindow.xaml I have:

<Window x:Class="MyProject.MainWindow"
        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"

    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Shared;component/UI/Resources.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <TextBlock Foreground="{DynamicResource FooColorBrush}" Text="Hello world" />
</Window>

Expectation is that the foreground color would be changed to the value I set at runtime in my App.xaml.cs (Color.FromArgb(255, 255, 255, 0)) rather than the color that's defined in the shared resources xaml file (<Color x:Key="FooColor">#FF00FF00</Color>)

1

There are 1 answers

0
Vg0 On

Figured it out. All I had to do was remove the MergedDictionaries from my MainWindow.xaml. My App.xaml.cs code was modifying the MergedDictionary of App.xaml, but since I also defined the MergedDictionary on my MainWindow.xaml, MainWindow.xaml was getting another copy of the resources which wasn't being overridden, and took precedence over the edited one from App.xaml.

Changed this:

<Window x:Class="MyProject.MainWindow"
        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"

    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Shared;component/UI/Resources.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <TextBlock Foreground="{DynamicResource FooColorBrush}" Text="Hello world" />
</Window>

To this:

<Window x:Class="MyProject.MainWindow"
        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"
    <TextBlock Foreground="{DynamicResource FooColorBrush}" Text="Hello world" />
</Window>

Alternatively, I could have added my logic for changing the resources to my MainWindow.xaml.cs:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.Resources.Remove("FooColor");
        this.Resources.Add("FooColor", Color.FromArgb(255, 255, 255, 0));
    }
}