steveh
Topic Author
Posts: 25
Joined: 07 Oct 2019, 12:50

Dynamic Resources

28 Oct 2019, 19:42

Hi guys,

I'm trying to implement a dynamic colour system in our game, so our entire UI can change the colour. In our main resource dictionary, I have something like this:
Application x:Class="OurNamespace.OurApp"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:OurNamespace"
             xmlns:noesis="clr-namespace:NoesisGUIExtensions"
             StartupUri="Startup.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="ColourResources.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:System="clr-namespace:System;assembly=mscorlib" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">
    <Color x:Key="OurBlue">#FF009AD7</Color>
    <Color x:Key="OurPink">#FFDE007D</Color>
    
    <SolidColorBrush x:Key="PrimaryColourBrush" Color="{DynamicResource PrimaryColour}" />
    <SolidColorBrush x:Key="SecondaryColourBrush" Color="{DynamicResource SecondaryColour}" />
I then want to define PrimaryColour from code. I've currently created something like the following snippet.
void SetPrimaryColour(NsString Primary)
{
	ResourceDictionary *pResources = GetApplicationResources();
	if (nullptr != pResources)
	{
		Noesis::Ptr<BaseComponent> pPrimaryColourResource;
		if (pResources->Find(ResourceKeyString::Create(Primary.c_str()), pPrimaryColourResource))
		{
			pResources->Set(ResourceKeyString::Create("PrimaryColour"), pPrimaryColourResource.GetPtr());
		}
	}
}
This asserts in ResourceDictionary::CheckReadOnly because I'm trying to modify a read-only resource database. So I tried to create my own, add it as a merged database, and update the resource in my mutable resource dictionary, but this doesn't seem to update any of the elements with bindings to the dynamic resources.
void CreateMutableResourceDictionary()
{
	ResourceDictionary *pResources = GetApplicationResources();
	if (nullptr != pResources)
	{
		m_pMutableResources = MakePtr<ResourceDictionary>();
		pResources->GetMergedDictionaries()->Add(m_pMutableResources);
		SetPrimaryColour("OurBlue");
	}
}

void SetPrimaryColour(NsString Primary)
{
	ResourceDictionary *pResources = GetApplicationResources();
	if (nullptr != pResources)
	{
		Noesis::Ptr<BaseComponent> pPrimaryColourResource;
		if (pResources->Find(ResourceKeyString::Create(Primary.c_str()), pPrimaryColourResource))
		{
			// Set resource colour on mutable resource dictionary, this doesn't assert but doesn't work either.
			m_pMutableResources->Set(ResourceKeyString::Create("PrimaryColour"), pPrimaryColourResource.GetPtr());
		}
	}
}
This method sidesteps the assert, but ultimately it doesn't actually update any of the resources which reference the dynamic resource (e.g. anything bound to the PrimaryColourBrush resource does not update). I am using DynamicResource everywhere in the XAML source files, but looking through the Noesis API it seems that there are no references to NotifyDictionaryChangedAction_Add and NotifyDictionaryChangedAction_Replace enums, so I don't see how the bindings are supposed to update and respond to changes in the mutable resource dictionary. Am I missing something, or does Noesis not yet support changing resources dynamically in code?

I'm a bit lost now. It feels like I'm not working within the system so I'm guessing I'm going about this the wrong way. Do you have any suggestions for ways in which I can achieve what I'm aiming for?

Cheers,

-Steven
 
User avatar
sfernandez
Site Admin
Posts: 1912
Joined: 22 Dec 2011, 19:20

Re: Dynamic Resources

29 Oct 2019, 10:09

Hi,

In current version Application Resources is a read only dictionary, so DynamicResources don't need to register against changes in that dictionary.
But that approach is going to change in our future major version because it doesn't match WPF behavior, where Application Resources can be set and modified. So your code will be valid to achieve what you want then.

In the meantime DynamicResources only respond to changes in the Resources of the UI tree. If you add a new dictionary to your xaml root, you can override there the colors along with the brushes that use these colors. Styles and templates can use DynamicResources to reference those brushes because they are instantiated in the tree, so they will find that new dictionary and apply the overridden brushes.

Do you think that could work for you?
 
steveh
Topic Author
Posts: 25
Joined: 07 Oct 2019, 12:50

Re: Dynamic Resources

29 Oct 2019, 11:16

That makes sense, thank you. I think I might be able to refactor it to use the brushes. I have some custom attached dependency properties which use these colours, but I could bind to the brush and use a converter to pull the colour from the brush instead.

Cheers,

-Steven

Who is online

Users browsing this forum: Bing [Bot] and 1 guest