dotnet / wpf

WPF is a .NET Core UI framework for building Windows desktop applications.
MIT License
7.05k stars 1.17k forks source link

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

Open dipeshmsft opened 3 months ago

dipeshmsft commented 3 months ago

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

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

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

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.

dipeshmsft commented 3 months ago

cc @miloush @batzen @pomianowski @ThomasGoulet73 @lindexi @MichaeIDietrich @robert-abeo @riverar @KirillOsenkov @Symbai

lindexi commented 3 months ago

Given the current time constraints, our development window is rapidly closing. I am inclined to opt for "Modify the fluent theme resources and styles to fit in the current system". My rationale is that it's preferable to choose a fully functional option with minor flaws, rather than a more refined but potentially incomplete solution. There's no perfect balance between functionality and resource allocation. My only concern is that this choice might result in legacy issues, making it difficult to modify the framework behavior in the future.

Currently, my concerns are as follows:

  1. The extent of testing on Fluent: I worry that it might necessitate patches immediately after the release of the ".NET9" version.
  2. Compatibility issues: This could potentially make it difficult for the project to upgrade from the old framework to the new version.
  3. Performance issues: I've noticed that the current styles heavily utilize DynamicResource. As is widely known and as @dipeshmsft pointed out, this could impact software performance. Fortunately, performance isn't a critical issue and can be continuously optimized in subsequent framework versions.
miloush commented 3 months ago

Thanks Dipesh!

First of all, I don't think the Fluent theme should become the default theme. It is designed for different kind of apps (with less information density) than what I expect most developers to be using WPF for, and it could hamper the adoption of newer .NET versions. I am open to be convinced otherwise, but I would think we should have a few releases with the theme shipped and perfected before making it default.

Second, a theme should be a "proper" theme. Having it in App.xaml as merged dictionary (i.e. "implicitly loaded" above) is not how themes should be shipped or used in production. In addition to the issues discussed above, it changes the precedence of resources for dependency properties. However, I understand that not everything is or will be ready in time for .NET 9 and if we want to keep the new theme "for testing" through next release, I am guessing keeping it as is would continue to serve the purpose.

For the technical concerns raised:

That makes me support the "Modify the fluent theme resources and styles to fit in the current system" option.

My preference would be: If there is time:

If there is no time, continue having the theme available for testing and debugging purposes "on the side" for .NET 9, but do not ship any API changes in support of it.

Symbai commented 3 months ago

Lets say I have made an app which I have overridden some colors on some controls for some purpose. Then I just recompile it on .NET 9.0 or whatever and suddenly it has this "fluent theme" which then collided with my changes. I don't think this is a good idea. IF you make breaking changes then it should be something worth it. Like WPF now allows AOT, trimming and what not. (and they're on by default) Then I would be okay with making these changes too. Not because they are necessary but because we are already having huge breaking changes that it won't matter anyways. But we don't have them yet. The only thing we have is this fluent theme which, at the time I was testing it, contains issues. It makes no sense to me to make fluent theme a default theme, at this moment! This is not a technical perspective but a rational.

dipeshmsft commented 3 months ago

Before this discussion moves on, when talking in terms of .NET 9, there will be a switch that will allow the framework to load Fluent as the default theme. I know there are issues with styles and Fluent specific style for all controls is not yet present, so there is no question of Fluent being system theme by default.

@miloush @Symbai @lindexi, hope this clears our stand when we are talking about Fluent as default theme.

As mentioned above, there are wide differences in the capabilities of both methods. In the current system, there is flexibility of overriding brushes and colors, referencing default styles and creating custom styles and this will setup a precedence that all of these features will be supported in next versions. However, loading as default ( still opt-in ) currently does not support all this, so moving ahead we will be adding functionalities to the theme rather than subtracting them.

Loading themes implicitly, i.e. adding the fluent dictionary to app.xaml is always present as a choice to developers to support higher level of customizations.

Coming to the API proposals, there are two proposals that we can work on :

robert-abeo commented 3 months ago

There is a lot to this discussion:

I was expecting you all to ship this with the current method: implicit styles that we have now registered in the app merged dictionaries overriding the theme styles. That said, I have personally encountered the issue of theme styles being used for programmatically created controls and then design inconsistency as the style is forcefully changed. It's not ideal in this way but seems the lesser of two evils (different for all of your assessments above).

The reason I say this is the lesser of two evils is simply because we MUST have access to the resources in the fluent styles. There are several custom controls that need to use shared resources (by key) in their control themes. Accent button is one example noted above as well. All of the Fluent v2 theme is designed to work this way and all existing code (even in WPF) is setup to use this. We are going to have a really difficult time moving away from other Fluent theme implementations if we loose this capability here. It's probably going to end up meaning we just copy the theme and register it in merged dictionaries ourselves.

As far as dynamic resource usage everywhere, it's required because in modern windows we are expected to be able to dynamically change between light/dark themes. I suppose I would be OK with a mechanism that supports this change only at startup rather than runtime though. Still, ThemeResource in WinUI is looking important right about now.

The concern about Fluent NOT being the default theme I somewhat agree with. Most legacy applications are designed for different information density than modern Windows desktop apps. HOWEVER, we have the compact density styles in WinUI to compensate for this. Hopefully that will be carried over here but I haven't dug into the code in that area.

Personally, like WinUI/Uno/Avalonia, I would expect a way to choose the theme in the application class at startup. In WinUI2 you could switch between Fluentv1/2 as desired and set the density style. Avalonia also allows registering the theme to use in App.xaml and there are a number of themes available even from 3rd parties. WPF locking this all down for theme styles and registering them behind the scenes was a mistake.

There are too many points to address right now but I'm advocating for just using the method we have now:

  1. This is best for compatibility with existing Fluent themes (we have to transition slowly from ModernWPF, etc.)
  2. This allows using the Fluent theme in older Framework applications (just have to copy/paste some code)
  3. We have access to the very important resources by key to use in custom controls and for things like accent button style
  4. We can still dynamically switch light/dark/etc at runtime and really do whatever we want by modifying the application-level merged resource dictionaries.
  5. We DON'T break any existing apps because behind the scenes we are still loading Aero2 as the theme by default and then just adding on top.

The ONLY downside I see to this is for programmatically generated elements like popups that might retain Aero2 in some cases. But I consider that the lesser of two evils until the WPF theme system is upgraded to support what we need here (as discussed in the original description). My assumption is we can move to a more integrated design in the future with minimal breaking changes.

miloush commented 3 months ago

we MUST have access to the resources in the fluent styles. There are several custom controls that need to use shared resources (by key) in their control themes.

Can you give some examples beside the accented button?

As far as dynamic resource usage everywhere, it's required because in modern windows we are expected to be able to dynamically change between light/dark themes.

You don't need dynamic resources for that, just two versions of the theme.

robert-abeo commented 3 months ago

Can you give some examples beside the accented button?

No, I can't share specific code examples. But think of it this way: If you are writing a ColorPicker or other custom control you need to have access to the underlying Fluent theme resources. These resources are consumed by all custom controls to implement their themes that match Fluent. If you are using nothing but stock controls, sure, you can let it all be hidden away. But as soon as you start extending things you need access to the keyed resources. (Please don't recommend duplicated code here too).

Edit: Another few cases in an existing app: accent colors need to be customized (user has some ability to adjust themes) and certain in-box control themes are customized too. If you can't have access to the underlying resources (think colors, brushes, etc.) this is a lot more difficult.

You don't need dynamic resources for that, just two versions of the theme.

That's a lot of duplicated code that is definitely worse in my book that using dynamic resources. If the two themes could be GENERATED from what we have now I would be OK with it. But we are well past the point in time where it makes sense to duplicate code like this.

miloush commented 3 months ago

I meant examples of resources you think need to be accessible.

If you are writing a ColorPicker or other custom control you need to have access to the underlying Fluent theme resources.

Which ones?

We have had the current system for years spanning several themes, so it's not like new limitations are being introduced. If you are lacking features, it would be useful to keep track of them.

If the two themes could be GENERATED from what we have now I would be OK with it.

Sure, that's how it has been for decades now.

https://github.com/dotnet/wpf/blob/6d26b95c22b59c1ba61da75c44cb829b9b181626/src/Microsoft.DotNet.Wpf/src/Themes/XAML/GroupBox.xaml#L97-L138

robert-abeo commented 3 months ago

@miloush You misunderstand my viewpoint. I have used the existing Fluent v1/v2 themes in UWP/WinUI and am currently using a customized version of ModernWPF that supports Fluentv2. What I am referring to are features that are expected in modern Fluent themes. I'm not referring to features that are in legacy WPF. So when you say "We have had the current system for years spanning several themes" that's true BUT we have all moved past that with third party libraries now.

For example, all Fluent2 themes for WPF (third party) have used the dynamic resource approach or some variant that allows switching between light/dark WITHOUT duplicating the entire theme and customizing it for light or dark. What I'm saying is the ecosystem has evolved quite a bit here and the expectations are now different than what was in Aero2. If you take a lot of that functionality away we simply will not be able to use the Fluent2 theme in WPF and will continue using third-party implementations that have the expected functionality. I'm trying to make it possible and more streamlined for those applications that are already using a third-party Fluent2 theme to be able to migrate to the official one here.

I'm not going to invest the time digging up all the Fluent2 resource keys we use in custom controls right now. I think I was clear in why it's important to be able to access resources by key:

  1. Custom controls that need to implement Fluent styles themselves need access to the underlying colors/brushes
  2. Modification of in-box control theme styles (using the same resources where needed)
  3. Theme modifications to the existing Fluent that change the accent color based on user settings (this means need to change the accent colors dynamically). This is actually more complex than just accent color though, a custom "blue" theme (like in Office) is needed where the backgrounds are changed to blue. That involves overriding a number of background brushes by key and is possible with all 3rd party Fluent themes right now but as I understand it WOULD NOT be possible with a system theme style.
miloush commented 3 months ago

I believe 2. was explicitly stated as undesirable. For 3., the colors and brushes in SystemColors can be overridden, it's only string keys that cannot be looked up. Basically there needs to be a contract between themes and the framework of known resources. To extend the current contract, you need to know which ones are missing for 1.

I'm not going to invest the time digging up all the Fluent2 resource keys we use in custom controls right now.

That makes it difficult to argue a point, I am sure your experiences would be valuable. There is no need to list them all. If you can find a few, especially referencing a Style like in the case of accented button, it would be helpful.

I'm trying to make it possible and more streamlined for those applications that are already using a third-party Fluent2 theme to be able to migrate to the official one here

I don't remember that being a goal at any point. People are also free to continue using whatever works for them.

What I'm trying to avoid is 1) having two completely separate, incompatible theme systems 2) unnecessary development and maintenance of something that will be obsoleted with next theme 3) significant performance degradation.

batzen commented 3 months ago

@miloush

  1. You can't use the keys from theme resources as they are mangled.
  2. As i said when the Fluent efforts started: WPF now has to compete with decades worth of development of third party libraries. If it's in no way customizable people won't use it. Not even i would use it if I could just use a much more flexible third party solution.
  3. Have you measured that? Especially when using a WPF version with my DynamicResource PR?
dipeshmsft commented 3 months ago

@batzen

You can't use the keys from theme resources as they are mangled.

Mangling is something that we can control,, earlier it was done for optimization and because developers did not have access to the string based key resources. So, not mangling but being able to find string based key resources in theme style resources is the issue.

Have you measured that? Especially when using a WPF version with my DynamicResource PR?

We haven't tried this yet.

@robert-abeo

2) unnecessary development and maintenance of something that will be obsoleted with next theme

Regarding the point @miloush said, although loading in app.xaml gives us a great amount of flexibility and even if we continue with the same model, I don't think that is the right places as it disables the scenarios where Application instance may not be present. It would have to be in a more neutral location.

That's a lot of duplicated code that is definitely worse in my book that using dynamic resources. If the two themes could be GENERATED from what we have now I would be OK with it. But we are well past the point in time where it makes sense to duplicate code like this.

For this, I have written a script to combine the resource dictionaries into one, similar to the ThemeGenerator that we have for earlier themes. I will put it up by the end of the week.

riverar commented 3 months ago

After a quote, be sure to leave a blank line or your answers will also appear quoted.

// Incorrect
> Question
Answer

// Correct
> Question

Answer
miloush commented 3 months ago

@batzen I expected my comment would make you join and reiterate your point, however, I was hoping for some elaboration. What customizations are you looking for? Can anyone give some concrete examples? Otherwise this discussion is hypothetical and no one can suggest how to proceed.

If it does not have to compete with those, or at least delivering the building blocks, i hardly see any reason copy/pasting the code from WPFUI to be WPF code base. ref

I am assuming the reason the the team went for Fluent theme and stopped doing everything else for a year or two is because it is the most upvoted issue in the repo. Based on comments on the issues (or lack of thereof), barely anyone of the supporters care about customization.

You can't use the keys from theme resources as they are mangled.

You cannot use string keys. I gave an example how colors and brushes from SystemColors can be used and we can do similar for new ones that are missing. It's the (one) complete style that is currently without precedence doing this way, although it could work similarly.

Have you measured that?

What exactly? Using proper theme vs merged dictionary? Or redesigning the theming infrastructure to support string keys and/or dynamic resources? I have not. For some reasons we keep accepting PRs that presumably bring low number of nanoseconds improvements in edge cases, while themes affect every piece of UI in every app all the time. So I want to be careful. I didn't claim either way. Clearly software like Visual Studio managed to do their own theming with performance they find acceptable without using "proper themes", so there are viable alternatives.

it disables the scenarios where Application instance may not be present

@dipeshmsft you don't have to merge the dictionary at an Application level, you can do it at Window or any element level.

One thing I haven't said yet is if people are not interested in the existing infrastructure and are happy with the Fluent theme being a separate library with a dictionary to be merged in, e.g. with help of attached properties, and if all the keys needed for customization were defined in that library rather than PresentationFramework, then I have no objections and no concerns.

IrinaPykhova commented 3 months ago

can you clarify, default System theme, does it mean some specific OS? Is it about Win 11 only? What would happen if application using this theme will run on Win 10? I'm asking because I wasn't able to install your Fluent demo app on Windows 10 machine

miloush commented 3 months ago

@IrinaPykhova I believe the intention with the theme being default would only be when run on Win11.

IrinaPykhova commented 3 months ago

@IrinaPykhova I believe the intention with the theme being default would only be when run on Win11.

in this case I don't understand how to properly work with it. You can apply theme and customize something. Then someone will run your application on Win10 and it will look absolutely odd with dated aero2 and your changes made for Win11

robert-abeo commented 3 months ago

@miloush Bluntly speaking, have you ever used Fluent2 theme before either in WinUI or one of the 3rd party libraries? I mean actually use it in a production app? You are taking positions I would not expect someone to take who has real-world experience. I've used Fluent2 since UWP/WinUI2 (being part of the discussion before it was released) and also a derivative of ModernWPF -- both in production apps. I've also used and contributed to FluentAvalonia as well. I have years of experience with Fluent2 theme usage in production.

I believe 2. was explicitly stated as undesirable.

What? You do realize that modification of in-box control themes is a fundamental feature of WPF? You can derive from an existing control, re-template and make it look like a completely different control. This is used all over the place. DO NOT get in the way of application developers delivering on what their designers and management has decided. That is not Microsoft's place and there is always an exception to the rule (you never know what's best for an individual application).

That makes it difficult to argue a point, I am sure your experiences would be valuable. There is no need to list them all. If you can find a few, especially referencing a Style like in the case of accented button, it would be helpful.

This comment specifically makes me think you've never used Fluent2 before. The theme is designed with a hierarchy of resources. There are the base resources that are then used in the control-specific resources which are then used in the control theme styles. We need full access to at MINIMUM the base resources by string key: https://github.com/dotnet/wpf/blob/e1e077d18fd13c365b13bb01a9dcfa5adb62f4dd/src/Microsoft.DotNet.Wpf/src/Themes/PresentationFramework.Fluent/Resources/Theme/Light.xaml#L25-L309.

I'm trying to make it possible and more streamlined for those applications that are already using a third-party Fluent2 theme to be able to migrate to the official one here

I don't remember that being a goal at any point. People are also free to continue using whatever works for them.

It seems obvious that needs to be a goal. WPF by Microsoft is VERY late to the game with a Fluent2 theme and most applications have had to switch to 3rd party solutions. You need to learn from those 3rd party solutions and then provide a pathway to bring everyone to the first party theme. You realized this yourself when you based WPF's theme on an existing 3rd party library.

What I'm trying to avoid is 1) having two completely separate, incompatible theme systems 2) unnecessary development and maintenance of something that will be obsoleted with next theme 3) significant performance degradation

1) No, what we have RIGHT now with implicit themes is not incompatible with anything. It's what everyone has lived with so far and is used to for Fluent2. As stated elsewhere of course you can register the styles at the Window level if you have a different application class structure as well. it is the most versatile. You can't say this is incompatible in any way.

2) That could be true because long-term we do need to switch to a more integrated theme due to the code-generated controls problem. However, we absolutely need features that don't exist right now to do that. Not only resource

3) I've seen no evidence of "Significant performance degradation" in real-world apps using existing 3rd party Fluent themes that use loads of DynamicResource references. I think what you are saying is most theoretical and we would have to quantify it with some actual data. Arguing this point theoretically probably isn't productive and my viewpoint is we can't sacrifice functionality regardless. We need access to resource keys, dynamic theme switching, and modification of in-box control themes.

Can anyone give some concrete examples? Otherwise this discussion is hypothetical and no one can suggest how to proceed.

As stated, this indicates you have NEVER used the Fluent theme. The concrete examples are the way the Fluent theme is designed. Again, ALL OF THESE RESOURCES are expected to be used in control resources and then those control resources in the default control styles/templates.

https://github.com/dotnet/wpf/blob/e1e077d18fd13c365b13bb01a9dcfa5adb62f4dd/src/Microsoft.DotNet.Wpf/src/Themes/PresentationFramework.Fluent/Resources/Theme/Light.xaml#L25-L309

Edit: And that's saying nothing of the "lightweight styling resource" concept that is used quite a few places. You sometimes need to inject an override to the control resource in the visual tree to change something without re-templating. Again, a pretty fundamental concept with modern XAML and the Fluent2 theme.

You cannot use string keys. I gave an example how colors and brushes from SystemColors can be used and we can do similar for new ones that are missing. It's the (one) complete style that is currently without precedence doing this way, although it could work similarly.

String keys are the most important considering how Fluent is designed.

If you work with Microsoft I highly, highly suggest you get in contact with the WinUI team to discuss this further internally.

@dipeshmsft

unnecessary development and maintenance of something that will be obsoleted with next theme

Regarding the point @miloush said, although loading in app.xaml gives us a great amount of flexibility and even if we continue with the same model, I don't think that is the right places as it disables the scenarios where Application instance may not be present. It would have to be in a more neutral location.

As stated, you can register control styles anywhere in the visual tree. If you don't have an application class register at the window. If you don't have a window, well, you don't need to register styles anyway.

That's a lot of duplicated code that is definitely worse in my book that using dynamic resources. If the two themes could be GENERATED from what we have now I would be OK with it. But we are well past the point in time where it makes sense to duplicate code like this.

For this, I have written a script to combine the resource dictionaries into one, similar to the ThemeGenerator that we have for earlier themes. I will put it up by the end of the week.

Yes, that's great in that regard. I know it's common to merge individual files into one single Generic.xaml file as well due to not only performance but to avoid circular-references. If there were two separate light/dark (High-contrast, etc. as well) files that could be switched out I would be fine with that. The issue is still no ability to reference the base resources by key for usage in custom controls and re-templating, etc.

miloush commented 3 months ago

You realized this yourself when you based WPF's theme on an existing 3rd party library.

@robert-abeo I am not involved in the theming work and I certainly wouldn't have done that if I was. The team is asking the community on their opinion given their progress and time constraints, you having more experience in this area than others should make it easier to answer questions and argue for your preferences.

As I said I have no issues with this continuing to be a mergeable dictionary with resources lookable by string (as long as it doesn't involve diverting API changes). That wasn't one of the two options given, but I am guessing it should be possible, at least for the upcoming release.

riverar commented 3 months ago

The original post was difficult to understand, so I will provide some general requirements and defer to you and others for the best implementation:

Allow us to:

I believe it is important to note that the adoption of WinUI outside of Microsoft is generally quite low, particularly when compared to WPF and WinForms. Therefore, I do not believe it is necessary to align any WPF work with any practices or standards set by WinUI 3.

robert-abeo commented 3 months ago

Therefore, I do not believe it is necessary to align any WPF work with any practices or standards set by WinUI 3.

I disagree here in that the goal should be to be visually as close as possible to WinUI3 (Fluent for web as well). We should also use the same resource keys (and control template structure) wherever possible. Originally, the plan was to generate as much as possible (even across frameworks) from the same design tokens. Keep in mind a goal of Windows 11 was to unify the UI as much as possible and WinUI3 IS the source of truth for that effort.

It is generally harmful for the overall ecosystem to unnecessarily re-invent the wheel especially when there are those of us that have to use multiple XAML frameworks. If there are places where deviation must occur due to different technologies that is understandable (several of these are known already).

riverar commented 3 months ago

I'm not against consistency with WinUI, where possible. But I don't think the team should spend too many cycles trying to align to something developers do not use or care about.

dipeshmsft commented 3 months ago

in this case I don't understand how to properly work with it. You can apply theme and customize something. Then someone will run your application on Win10 and it will look absolutely odd with dated aero2 and your changes made for Win11

Yeah, this seems to be a bind right now, because some of the DWM APIs that we use are only available since build 22621. We are thinking about it in parallel.

@robert-abeo

You do realize that modification of in-box control themes is a fundamental feature of WPF?

It's not like if the resources are loaded as theme ( from here on I will refer it as default ) styles are not stylable. Even earlier, developers could base there custom styles on default styles and modify the properties themselves.

Your concern, regarding not being able to use string keys for creating a new custom style is right in its place, this is something that is not present in the current theme infrastructure of WPF, because earlier Windows used to use SystemColors for visual styles and WPF being built at that time followed the same thing.

It seems obvious that needs to be a goal. WPF by Microsoft is VERY late to the game with a Fluent2 theme and most applications have had to switch to 3rd party solutions.

With recent changes in Windows, I believe there was a shift in design principles and with Fluent coming in things have changed, and no doubt WPF doesn't support the modern ways. We have a lot to cover in terms of themes, styling, the level of customization and flexibility, and we want ( yes, things are moving slowly, I guess slower than what developers have expected so far ) to provide this to our developers, but that also means it will take time.

But at the same time, we also need to take care of the systems and compoenents that are in place, and that is why this thread was started in the first place. And that is what @miloush is advocating here. I agree with this point of view. As you mentioned, this is not the long-term solution, and this is my stand as well, because we had to add in checks everywhere ( and I guess we have missed it at places as well ).

And since this is not a long-term solution, any changes that come in future may require developers to respond to that, which I believe, will not be a good experience for many developers out there. Surely, default theme as opt-in option is also not the ideal way to do things, but what that does is, it allows us to add flexibility and customizability to the theme in next release.

As stated, you can register control styles anywhere in the visual tree. If you don't have an application class register at the window. If you don't have a window, well, you don't need to register styles anyway.

Yes, obviously we can do that, but that also means we will have to take care of Window, and add a check to see if fluent is loaded in window and allow for dynamic switching.

MichaeIDietrich commented 3 months ago

The general question is who is the target audience for the introduction of the Fluent styles in WPF?

If you ask me it's mainly for the existing WPF applications out there that use the built-in vanilla theming system and not any of the 3rd party theming libraries (i.e. MahApps, ModernWpf, ...).

I say so because WPF's theming system is meant to be OS design agnostic with automatically applying a theme that tries to mimic the OS visuals. This is true for XP, Vista/7, 8 (Win10 was sadly ignored since UWP was in focus) and in my opinion should also become true for Win11 with the current effort. (still an opt-in/out may be useful)

This means it should work the same way as the previous themes worked without manually referencing it in the App.xaml. The approach to merge it with the current Aero2 theme is too flawed and hacky, beside the already mentioned issues with implicit styles in e.g. DataGrid, it also breaks common styles that look like the following:

<Style Target="Button">
  <Setter Property="FontWeight" Value="Bold" />
</Style>

as it would apply the Aero2 style button theme.

WPF's Fluent styles should look as close as possible to WinUI styles like Fluent UI for web does. I think there is a common ground here. Still, I don't really see the argument in making WPF styling system to behave exactly like WinUI's in all terms from the beginning, we should better start with the existing infrastructure to provide the Fluent styles and iterate to extend it to better support scenarios that are not yet really supported.

Looking at our time constraints this looks to me like the most reasonable path. It still will take its time until developers actually adopt this new theme.

And to mention Win10, I think WPF's Fluent styles should also work on Win10, since WinUI does also work on Win10.

dipeshmsft commented 3 months ago

@riverar

Apply modern styles to controls (e.g., slider) individually without affecting the rest of the application. Avoid using the new theme altogether (opt-in or opt-out is acceptable).

In either of the scenarios, the way of loading the themes will be optional.

Override the appearance of any controls using the new style (e.g., to fix errors or add missing functionality).

That's in place in the new styles.

Access current/dynamic color/design tokens programmatically (e.g., current accent color for injection into the acrylic tint layer, high-contrast scenarios, etc.) Currently, we use uxtheme and other documented/undocumented APIs, but none of them are accurate. The only reliable source for accurate color tokens is WinUI 3.

We have discarded the use of undocumented DWM APIs and depend on same source as WinUI for accent colors

Support Windows 10 downlevel (if this is within scope; otherwise, please disregard).

We are working on this, support for Win 10 is absent currently due to calls to some DWM APIs that are present only in Win11.

robert-abeo commented 3 months ago

@dipeshmsft

It's not like if the resources are loaded as theme ( from here on I will refer it as default ) styles are not stylable. Even earlier, developers could base there custom styles on default styles and modify the properties themselves.

You can override the default styles, yes. But you cannot easily customize them and replace the control template because you don't have access to the base and control-specific color/brush resources (this is what I'm referring to which is the same string key issue). You will have to manually re-create all the control brushes which is undesirable to say the least and not something we have to do with third-party libraries today. It's also not something that has to be done with existing WPF themes because the system colors are always available as you said.

Option 1

Without the core changes to themes in WPF (to support string key reference lookup, dynamic light/dark switching, compact density, theme switching, etc.) I would say it is a non-starter for us. Reading above where there are others using Fluent themes already that share this viewpoint. There is functionality we absolutely have to have 18 years later. Without that we can't migrate existing code.

If I was making the call here I would make the theme fully optional and not fully integrated in .NET 9. I would design it exactly as other third party themes today and require developers to manually register it in the visual tree or app where it's needed. You can provide a reference to the compiled Fluent Generic.xaml and related light/dark resource dictionaries and we can switch it out ourselves manually -- even for individual controls. Deliver what we know already works with maximum control. Yes, that will have to change in the future -- BUT it can be done non-breaking, you just have to keep supporting a hybrid approach.

If it takes another year to fully integrate this as a default theme that's fine as far as I'm concerned.

Option 2

For backwards-compatibility a hybrid approach is probably going to be required long term anyway. That could be done now I suppose. This means you do register Fluent as the default BUT ALSO provide most of the resources in a resource dictionary accessible to apps by string key. Duplicated resources.

This seems like a problem now too though because of existing apps that expect Aero. It would eliminate the special casing with certain controls built in code.

Option 3

Somehow find the resources to make the default themes do what we need before .NET 9. This is bringing the long-term solution forward to the initial release. Based on the issue description I think this would be very difficult.

robert-abeo commented 3 months ago

@MichaeIDietrich

If you ask me it's mainly for the existing WPF applications out there that use the built-in vanilla theming system and not any of the 3rd party theming libraries (i.e. MahApps, ModernWpf, ...).

I disagree because those apps that are NOT currently using Fluent are those apps that 1) Are so ancient they don't follow latest design conventions anyway or 2) Don't follow Fluent because of issues like information density, etc.

If we don't take an approach that works with apps using existing third-party themes today you will cause issues with both classes of users out of the gate. Using the existing 3rd party library techniques means we can quickly bring those apps into the WPF native theme and all other apps that are using ancient styles can continue to not update and be happy. Worse case they do update and then we may only cause trouble for one class of users.

Finally, without access to the underlying resource by string key absolutely everyone that attempts to use Fluent and customize it is going to face a challenge -- and they will be vocal about it.

I say so because WPF's theming system is meant to be OS design agnostic with automatically applying a theme that tries to mimic the OS visuals. This is true for XP, Vista/7, 8 (Win10 was sadly ignored since UWP was in focus)

Win8/10 was also ignored because the Metro/WinRT styles in the beginning simply could NOT work with existing desktop apps. They were designed for mobile-sized displays with very little information density -- remember giant rectangle buttons with an icon and cards in a GridView, no corner radius support? Fluent doesn't suffer this problem and works across all platforms. It's actually desktop focused again.

I do generally agree that stock WPF should continue the trend of just matching the OS. We are also in agreement on the long-term direction here. We just can't get there due to technical limitations right now.

riverar commented 3 months ago

I disagree because those apps that are NOT currently using Fluent are those apps that 1) Are so ancient they don't follow latest design conventions anyway or 2) Don't follow Fluent because of issues like information density, etc.

No, that's not right. WPF app developers don't use Fluent because they do not have access to the necessary design tokens, styles, resources, APIs, docs, etc. to properly do so. The knowledge is all encoded into WinUI 3 and no where else. MahApps, ModernWpf, etc. are attempts to extract that information but I don't view them as reliable solutions.

robert-abeo commented 3 months ago

Note that ModernWpf is a direct port from WinUI3. I will expand this to three classes of apps though:

Class 1 : Using third party libraries for Fluent already Class 2 : Using Aero but want to use official Fluent Class 3 : Using Aero and don't plan to update.

If you force Fluent as the default style you will cause issue for Class 1 and Class 3. Class 2 will encounter problems as soon as they try to customize anything (I guess they don't have experience with Fluent at all yet).

If you go with what we have today you don't cause issues by default for any of the classes. Each is optional and we don't face technical issues trying to use the theme.

dipeshmsft commented 3 months ago

After going the discussions, and since each side has there own reasons to back it, I was thinking about enabling both the ways for .NET 9. Obviously, we will have to complete the API proposals before we can do that, but here are the reasons for doing this.

However, at the same time I understand that this can cause more confusion, and when we modify some of the infra that enables this right now, it may not sit well with the developers.

I would like to know your views on the above idea.

PS : As I mentioned earlier, that API Proposals are crucial here, I would like to have your comments if any on Theme switching (#8932) and AccentColor proposals (#9295).

robert-abeo commented 3 months ago

@dipeshmsft

A hybrid approach for now makes sense for me. We get Fluent2 by default and also get access to the much needed resources by string key as well. Not being able to access resources was the showstopper (assuming you keep most things DynamicResource still).

The only downsides are for class 3 apps (from the list here) that wish to keep using Aero2. However, as discussed above WPF historically has always matched the theme of the system. So it would make sense to continue that. Developers of those apps can continue to use .NET 8 until they are ready to update OR if Theme switching is done by .NET 9 there is no problem here either.

Assuming you can stop mangling the resource keys for theme styles in .NET 10 or so the additional implicit styles can go away too. I can't think that would be a breaking change, it would just remove the duplicate resources (and give a little bump in performance perhaps).

Hybrid provides a clean path for migration from third party Fluent2 and doesn't have any showstoppers I can think of. I support that direction.

dipeshmsft commented 3 months ago

@robert-abeo In the PR I mentioned above for enabling fluent, allows accessing Fluent color and brush resources, I have made them static though in that case for now. And after going through the discussions, it may not be a good idea to make Fluent default but that we can figure out later

Also, there is no mangling of the resource key in the PR above.

robert-abeo commented 3 months ago

@dipeshmsft I'm confused.

After going the discussions, and since each side has there own reasons to back it, I was thinking about enabling both the ways for .NET 9.

Sounds good.

And after going through the discussions, it may not be a good idea to make Fluent default but that we can figure out later

You seem to undo what you just said 30 minutes before. So I'm not sure why your thinking changed or if I am confusing some point.

Also, there is no mangling of the resource key in the PR above.

Most of the discussion above was based around this point. If we DO NOT have access to resources by string key then we can't use Fluent2. If we DO have access to these resources by string key the majority of my concerns are gone. I was under the impression (along with others) we WERE NOT going to have access to system theme style resources in .NET 9 no matter what. The technical changes just weren't ready. You said:

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.

The only concern remaining is DynamicResource usage.

dipeshmsft commented 3 months ago

You seem to undo what you just said 30 minutes before. So I'm not sure why your thinking changed or if I am confusing some point.

What I meant above was that, in the PR I have added an app context flag to allow loading fluent as default, in future we can have a different mechanism ( maybe something in app.config ) to enable fluent as default and keep Aero2 as default when the correct flags are not used. I am referring to the point that Fluent by itself is low density, and that can be an issue for developers. I hope this makes it clear.

If we DO NOT have access to resources by string key then we can't use Fluent2. If we DO have access to these resources by string key the majority of my concerns are gone.

The changes ( that allow searching for string resources ) may have other issues. Plus the DynamicResource usage is still something I have not tested out when using Fluent as default i.e. suppose you wanted to update any color or brush, how will it reflect in theme styles. Because theme styles are frozen and cached, currently the static values are realized at the time when styles are loaded.

I was under the impression (along with others) we WERE NOT going to have access to system theme style resources in .NET 9 no matter what. The technical changes just weren't ready.

I still think there is a lot of testing that needs to be done to validate the changes. At the time, when I started this thread, I had done some experiments, and I was getting many issues and the test apps were not working correctly. I think there may be some more issues that I have not hit, but for now, I got the WPF Gallery app working with these changes.

robert-abeo commented 3 months ago

I am referring to the point that Fluent by itself is low density, and that can be an issue for developers. I hope this makes it clear.

Have you looked into density styles yet? WinUI handles this case built-in: https://github.com/microsoft/microsoft-ui-xaml/blob/winui3/release/1.6-stable/controls/dev/dll/DensityStyles/Compact.xaml

The changes ( that allow searching for string resources ) may have other issues.

Ok, that's what I originally understood.

Plus the DynamicResource usage is still something I have not tested out when using Fluent as default i.e. suppose you wanted to update any color or brush, how will it reflect in theme styles. Because theme styles are frozen and cached, currently the static values are realized at the time when styles are loaded.

Yes, that is also a concern I noted above. However, it can be worked around with full re-templating. Not ideal but possible. Still, the light-weight styling concept was very useful in WinUI (where you inject a new resource by key directly in the visual tree at the level you want to modify -- without re-templating).

I still think there is a lot of testing that needs to be done to validate the changes.

Yes for sure.


If you want to just stay with what we have now (implicit styles registered in merged dictionaries) I'm also OK with that. Like I said above it doesn't by default break anyone's use case. It gives another year to make sure things are ready for default Fluent theme styles.

miloush commented 3 months ago

I will point out it's not "string keys" or "nothing". The assembly with the theme can expose it's resources that can be used as keys for lookup.

robert-abeo commented 3 months ago

@miloush

I will point out it's not "string keys" or "nothing". The assembly with the theme can expose it's resources that can be used as keys for lookup.

This has been discussed a lot above but I strongly disagree. It is basically "string keys" or "nothing". Without access to string keys you can't customize or use Fluent2 as it was designed. Yes, the app can just copy the entire theme in itself (which I said above we would have to do if you went this route) but that is defeating the purpose of providing a built-in Fluent theme. Why even bother at that point?

miloush commented 3 months ago

I don't see how that prevents you from customization of the theme. Instead of {StaticResource TextControlElevationBorderBrush} you would do {StaticResource fluent:ThemeResources.TextControlElevationBroderBrush} or something.

robert-abeo commented 3 months ago

@miloush

Yes, we can just provide our own color and brush resources, then our own styles and control templates we need to customize. In fact we can just provide our own theme. You are missing the point here.

Go use Fluent in real-world apps with WinUI 3. Learn about ThemeResource, the light-weight styling resource concept etc. Then use some WPF 3rd party Fluent theme libraries. With the same features supported by DynamicResource and the same string keys.

  1. Your suggestion of using a StaticResource breaks the ability to dynamically switch light/dark themes which we already have.
  2. You can't use light-weight styling resources injected in the visual tree at all because the core theme styles are static
  3. Re-templating we will have to copy out all the base resources again and put them in another resource dictionary... defeating the point of having a built-in theme. It's too tedious and error-prone to do this for individual resources:
  4. We are simply not going to spend the time to pull-out all the theme resources again (and you are not accounting for light/dark). Will just use a 3rd partly library or copy the WPF themes as-is right now and branch it internally.

I really don't think you understand how Fluent theme is used today and what we have in 3rd party libraries. We need others to jump in on this discussion to break the tie but then we just restart all over again. It's pointless at this point for me to debate this further with you.

miloush commented 3 months ago

Doesn't have to be static, you could as well do {DynamicResource fluent:ThemeResources.TextControlElevationBorderBrushKey}. I am setting aside the discussion on how themes should work or why, I am suggesting a compromise that gives you access to all the resources a theme deems to be replaceable without having to redesign the whole infrastructure.

robert-abeo commented 3 months ago

@miloush

Yes, I know you can use DynamicResource as well. But you are missing the forest for the trees. You cannot for some reason see the big picture here. If you were on my team you would be out of the discussion at this point.

SystemColors in WPF today is what we have to avoid the above. In Fluent the system colors are built-in as resources. You are essentially saying you can customize Aero2 without SystemColors. That's true but then you have to copy and re-create the entire theme piece-by-piece as needed. Of course the WPF designers thought that was bad practice so provided SystemColors to begin with. Of course we are not going to invest this level of effort either. We will just use another Fluent theme that does what it was designed to do and gives use the resources by default.

It's frustrating for me to debate this with you. You fundamentally do not understand my viewpoint and you do not understand Fluent. I will tell you for the last time: If you release Fluent as only built-in system theme styles with all the limitations discussed above it will be unusable for us. Since I have an enormous amount of experience with Fluent you might want to listen to this data point.

I'm now stepping out of the discussion. It's not worth my time going in circles like this.

miloush commented 3 months ago

You are essentially saying you can customize Aero2 without SystemColors

No I am saying the theme assembly can have its own theme-specific equivalent of SystemColors.

jaelys commented 2 months ago

I've been using WPF for more than 10 years, and I've had a lot of designs and user needs, so I'd like to share the actual development process

1.Win7, I pursue the establishment of acrylic effect, Win10, I pursue the establishment of Mica effect, can only simulate, the effect performance is not good, Win11, WPF is still in place, WinUI 3 sees hope, but can only wait, can not support my project production migration

2.Win7,I pursue Fluent,Win10,I pursue Fluent2,Win11...., yes, all my projects never use the system preset style and color, because whether it is custom or using a third-party Fluent control, I always have to copy and merge all the templates and style keys, including the style of handling light and dark, including the color of the system preset, to ensure that the definition is not repeated

  1. The types of projects are enterprise, tools, information-intensive, full-screen, touch screen, Iot, dashboard, ....., UI design always needs to include customization at the same time, Fluent, so I never use system presets, I hope that the project in Win7 Win10 Win11 are all the same design style, but also the current needs of all my customers, without exception, including pop-ups, notifications, prompts, window titles

I'm looking forward to WPF Win11 becoming the system preset, and if I can customize it directly with the preset, it will take more than a decade of burden off my mind to focus on functionality and performance optimization

In fact, most of the current third-party Fluent controls, I still have to extract some of them and re-customize the style, and I also have to understand how the third-party used was originally defined, and it would be best if WPF could be unified, so that third-party controls can focus on more control extensions, which is also better for the WPF ecosystem

I don't have great skills, but I love WPF