Skip to content

Proposal: Add override-aware indirection support to the XAML resource lookup system #2913

@Felix-Dev

Description

@Felix-Dev

Proposal: Add override-aware indirection support to the XAML resource lookup system

Summary

Currently, the XAML resource lookup system does not have support for override-aware indirection. By that I mean the following: If we have two resources with one resource referencing the other, the referencing resource should pick up developer-provided overrides of the referenced theme resource when in scope. To illustrate this, please take a look at the following XAML:

<!-- These resources are defined in some resource dictionary -->
<SolidColorBrush x:Key="BaseBrush" Color="LightBlue" />
<StaticResource x:Key="BaseBrushInheritor" ResourceKey="BaseBrush" />

And some XAML where these resources are consumed:

<StackPanel Orientation="Horizontal">
    <StackPanel>
        <Rectangle Fill="{StaticResource BaseBrush}" Width="150" Height="150" Margin="0,0,10,0" />
        <TextBlock Text="BaseBrush" Width="150" TextWrapping="Wrap" HorizontalAlignment="Left" />
    </StackPanel>
    <StackPanel>
        <Rectangle Fill="{StaticResource BaseBrushInheritor}" Width="150" Height="150" />
        <TextBlock Text="BaseBrushInheritor" Width="150" TextWrapping="Wrap" HorizontalAlignment="Left" />
    </StackPanel>
</StackPanel>

In the code above, we are creating two rectangles side-by-side with one rectangle consuming the referenced resource directly (BaseBrush) and the other rectangle consuming the referencing resource (BaseBrushInheritor). As we would expect, both rectangles are displayed in the correct color:
image

The issue arises when we now override the referenced resource, like so:

<StackPanel Orientation="Horizontal">
    <StackPanel.Resources>
        <SolidColorBrush x:Key="BaseBrush" Color="Orange" />
    </StackPanel.Resources>
    <StackPanel>
        <Rectangle Fill="{StaticResource BaseBrush}" Width="150" Height="150" Margin="0,0,10,0" />
        <TextBlock Text="BaseBrush" Width="150" TextWrapping="Wrap" HorizontalAlignment="Left" />
    </StackPanel>
    <StackPanel>
        <Rectangle Fill="{StaticResource BaseBrushInheritor}" Width="150" Height="150" />
        <TextBlock Text="BaseBrushInheritor" Width="150" TextWrapping="Wrap" HorizontalAlignment="Left" />
    </StackPanel>
</StackPanel>

This gives us the following result:
image

As we can see, the rectangle consuming the referenced resource (BaseBrush) correctly picked up our local override. However, the referencing resource did not. It still uses the the orginal value of the referenced theme resource, even though we have overriden that one in the correct scope. Ideally, the result here would be both rectangles displayed in an orange color.

I have attached a demo app featuring this code below.

Rationale

Adding support to the resource lookup system to pick up updates to referenced resources and make them available through the referencing resources will enable at least the following two scenarios:

  1. We would be be able to update WinUI's (theme) resources in certain cases without breaking apps of developers. For example, WinUI today ships with resources named incorrectly or imprecisely. With override-aware indirection support, we could add new resources properly named and make them reference the existing resource, ensuring that any app using the existing resource to customize its UI will still look as expected. Examples where this would be helpful can be found here, here and here (see the discussion on the proposed TopNavigationViewItemHeaderInnerMargin theme resource).
  2. We would be able to offer some "at all once" customization for related UI elements while still providing fine-grained customization support. An example for this can be found for the TextBox, ComboBox and NumberBox controls. All three controls have a Description API and the foreground appearance can be configured by overriding the SystemControlDescriptionTextForegroundBrush theme resource. In other words, overriding this resource on the app level, for example, will apply to the descriptions of all in-app TextBox, CombBox and NumberBox controls. However, for a consistent and easily discoverable lightweight-styling experience we should also think about adding specific theme resources like TextBoxDescriptionForeground, ComboBoxDescriptionForeground and NumberBoxDescriptionForeground. These three theme resources would reference the "parent" theme resource SystemControlDescriptionTextForegroundBrush so all overrides applied to it will still propagate down to its "child" theme resources while still allowing developers to pick a unique description foreground appearance for all three controls if they so wish. A discussion about this specific topic can be found here.

Additional context

There's also a perhaps related issue where resource lookup initiated by binding functions does not pick up overriden resources. You can find more info about that here.

Attached files

XamlResourceSystemLookupDemo.zip

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions