microsoft / microsoft-ui-xaml

Windows UI Library: the latest Windows 10 native controls and Fluent styles for your applications
MIT License
6.28k stars 675 forks source link

Updating ResourceDictionary in code behind doesn't fire change notification #4443

Open asklar opened 3 years ago

asklar commented 3 years ago

XAML Version: System XAML Scenario: When doing Hot reload in React Native, some styling needs to change as a response to the user changing app code out from under the app

  void SetResources(const xaml::FrameworkElement& fe, const JSValueObject& dict) {
    auto rd = ResourceDictionary();

    for (auto const& entry : dict) {
      const auto& name = entry.first;
      const auto& value = entry.second;
      auto brush = ColorUtils::SolidColorBrushFrom(value);

      rd.Insert(winrt::box_value(winrt::to_hstring(name)), brush);
    }
    fe.Resources(rd);
  }

Running through this code the first time correctly sets the value and it renders. The second time this code runs through, the control does not re-render. Removing the element from the ResourceDictionary does not fix it either

evelynwu-msft commented 3 years ago

This is expected and by design. {StaticResource}'s resource lookup logic only runs once, when the parser processes the markup (in this case, the template for the underlying native XAML control, e.g. Button). No mechanism exists for forcing the logic to run a second time to reflect changes to the ResourceDictionary hierarchy short of literally recreating the element using the {StaticResource}.

asklar commented 3 years ago

tagging @MikeHillberg, let's discuss this and the motivation behind this as a feature request :)

asklar commented 3 years ago

FYI @bartekk8

MikeHillberg commented 3 years ago

A StaticResource in markup is just like doing an assignment in code; to update it you need to re-execute it. Implicit styles and data binding are dynamic though, maybe we could use those as a mechanism here.

asklar commented 3 years ago

My expectation on how this should work, based on nothing but common sense :D :

  1. The Resources property says nothing about it being a static resource.
  2. This gets confounded by the fact that this seems like it just works in WPF but not uwp xaml
  3. First attempt was to set a new value in the ResourceDictionary. That should fire a notification on the children to re-evaluate. Nope!
  4. Ok, maybe I need to remove the element from the dictionary and set it again. Nope.
  5. Ok, maybe I destroy the dictionary and add a new one. Nope.

Agree that the main problem is the lack of a mechanism for children to be notified of an ancestor's ResourceDictionary changing. Do you have thoughts on how we can use data binding and implicit styles to achieve this? I'm looking at using ResourceDictionary in RNW to implement lightweight styling that can interface or at least be analogous with FURN

chrisglein commented 3 years ago

My expectation on how this should work, based on nothing but common sense :D

Agreed. The developer expectation is that these should be dynamic. WPF had DynamicResource and that doesn't exist in the StaticResource/ThemeResource system of system XAML and WinUI. It feels like a gap and one we need to resolve in the resource system design eventually.

asklar commented 2 years ago

Internal tracking: http://task.ms/39897009