Skip to content

Enabling Fluent as Default System Theme - Next Steps ? #9283

Open
@dipeshmsft

Description

@dipeshmsft

In WPF we have two types of styles for any FrameworkElement - Style and ThemeStyle. Style attribute allows developers to provide custom styles for the controls, whereas ThemeStyle provides a default style which will be used in the absence of custom styles provided by the developer or when developers override only a few properties for the control in the custom style. ThemeStyle ( from here on I will refer to them as default style ) is an internal property and developers don't have access to this property. The default styles are loaded by the framework based on the OS version and color scheme.

As of now, Fluent theme can be loaded by including the resource dictionary in App.xaml, which means that the framework treats them as non-default style and they are loaded in Style property for the framework. Ideally we would want to load them as default styles however, there are some constraints to that approach.

Constraints of making Fluent a theme style

  • Theme style lookup is different from the lookup of other styles. When a resource dictionary is loaded as default style, we can not search for resources ( like brushes , colors or styles ) which have a key of type string. Theme resource dictionaries are only searched for resources when the key is either a Type or a ResourceKey. This will prevent a developer from using resources defined in Fluent theme dictionary. Essentially, that means, we won't be able to access AccentButtonStyle, ControlElevationBrush, etc. by referencing them in custom style as it is possible in WinUI.
    <!-- These scenarios will be blocked, where AccentButtonStyle and ControlElevationBorderBrush is present in Fluent theme dictionary -->
    <Button Style="{DynamicResoucrce AccentButtonStyle}" />
    <CustomTextBlock BorderBrush="{DynamicResource ControlElevationBorderBrush}" />  
  • Theme styles do not support DynamicResource very well. Uptil now, if you had to use DynamicResource in theme style, you would have to use ComponentResourceKey or follow a pattern similar to SystemColors, where we have a set of colors and brushes that can be referenced. This restricts the way in which we can define and use accent colors and brushes. For theme dictionaries when we use DynamicResource, we get back DeferredThemeResourceReference instead of DeferredResourceReference, which gets inflated, frozen and cached.

To deal with the above constraints, we have two options :

  • Modify the fluent theme resources and styles to fit in the current system : That would require exposing public API for accent colors. Making some resources static, creating seperate theme files for light and dark mode ( we are on top of this already ).
  • Enhance the capabilities of theme resources : Allow searching for resources using string keys. Allowing DynamicResource to work with theme resource in full capacity. ( I have been working on this, but this is more complex than I thought and will require more time and efforts. ). This will also open up the framework for more flexibility, but at the same time make it easier for things to go wrong.

We don't face these issues in the current setup ( i.e. fluent theme resources are loaded in app.xaml ). In the current setup, the styles are treated as implicit styles ( when we don't provide a key for a style or we provide the Type as the key, it get's used for all controls without specifying it everywhere ) and we can search for any resource defined in the resource dictionary. Now, when we use this resource dictionary via app.xaml, DynamicResource works as we all know it.

Although the current setup is temporary, and even if we continue with the current setup in .NET 9, it has it's own disadvantages.

Issues with using Fluent as implicitly loaded style

  • Whenever, framework elements are generated via code ( like in DataGrid ) the framework creates the object and does not set the Style property, it relies on ThemeStyle for it's styling. This will cause inconsistent UI in the application. That is the reason why, we had to add checks at some places in code to maintain that consistency in UI. ( Still need some more investigations here )
  • It becomes very easy to modify resources. This can lead to different scenarios of using the themes, it makes it easy to remove some particular styles or resources which can again lead to inconsistencies in UI.
  • The whole setup depends on the presence of an instance of class Application, which may not be present in some scnarios. As this current theme loading and switching is temporary, and once we move from this model to the default one, we will hit the constraints there. Now, where we can access the resources by string key names, once we make the theme default, won't work anymore until and unless the capabilities of theme resource are increased. However, doing that would would essentially mean that we are treating resource names as public contracts, and would need to deal with performance issues.

Keeping in mind the time frame for .NET 9 and that we are already past preview 6, getting all the features completed is difficult. So, we would like to seek community opinion on what path shall we take for now.

Metadata

Metadata

Assignees

Labels

User StoryA single user-facing feature. Can be grouped under an epic.Win 11 Theming

Type

Projects

Status

🥅 Todo

Relationships

None yet

Development

No branches or pull requests

Issue actions