dotnet / wpf

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

Expose facilities for contributing to/controlling the WPF Themeing engine #1913

Open DigitlWorld opened 4 years ago

DigitlWorld commented 4 years ago

The themeing engine that WPF uses to apply Default Styles to all elements should be made available for application specific override/replacement rather than being locked to the 6 or so PresentationFramework.*.dll themes. Instead of relying on a fixed set of system themes (e.g. Aero, Luna, etc.) and related sub-themes (e.g. Luna.Metallic), partially forced by System settings and events, I suggest opening up this mechanism to allow application designers to fully control the actual default styles for their application.

The problem is that not being able to easily create/set default styles via themeing causes a great deal of downstream headaches for developers and designers when attempting to devise an entire replacement skin for an application:

If it's already possible to do what I'm suggesting, then consider this a documentation improvement request, as it isn't clear at all from the documentation as to how one would go about replacing the actual default styles.

weltkante commented 4 years ago

Just for the record, the builtin themes only work on the OS they are designed for, since they have plenty of dependencies on OS resources (size constants, color constants etc. are read from system parameters). Also Window frames are still drawn by the OS and not by the theme, so these won't fit the theme either. If builtin themes are supposed to be selectable for this new feature then they need to be made more independent from OS parameters.

If it's already possible to do what I'm suggesting

I think you can work around it by registering the theme resources you desire in the application resource dictionary. Resources keyed by the control type in the application dictionary should have higher priority than the themes and default styles I think, so you should be able to replace them there.

This can also use features like nested resource dictionaries, implementing the composition of the resource dictionaries in code, possibly switching them out at runtime to allow theme changes.

Its by no means easy or well documented but I think its already doable without any major hacks.

(That's not supposed to be an argument against opening up the theming engine to be more general purpose, I'm just mentioning it because it is an alternative solution to the original problem of making a themeable application.)

DigitlWorld commented 4 years ago

@weltkante If you merge the PresentationFramework.<theme>.dll resources into App.xaml's resource dictionary today (at least in .NET Framework 4.7.2) you're still left with the style override limitation. They still don't replace the default styles and providing a local style definition will still reset back to the OS-selected default style.

I agree that it would take making the WPF-provided themes more platform agnostic, but I have to imagine that's a good thing over the long-term. I understand the WPF roadmap is explicitly avoiding cross-platform ports today, at least any PRs aiming to provide that, but this would help start to prepare things for a world where that could happen (either here or in a fork).

I agree that despite the things you've mentioned, it would probably still be a good move for WPF to open the theme system and default styles mechanism up for direct application control.

weltkante commented 4 years ago

You are supposed to replace your "local styles" on the application level as well, theming is not something modular for two reasons:

My point is that the WPF theming engine isn't designed with modularity or 3rd party themes in mind, to make a proper theme your only chance is to replace everything at the application level with full knowledge of which controls the application uses.

So while opening up the theming engine would be nice, having proper third party themes probably needs more thought. For now application themes are a working way to do theming (but requiring lots of work to create and maintain in face of changes), I think we should keep the discussion going how to improve this and make the system more modular.


Having put some thought into this, right now I'm thinking for the sake of compatibility its probably better to provide a new extension point: if you have a 3rd party theme you want a way to override the default style and turn off the OS-specific theming. Even if the controls opted out of default styles via ThemeInfoAttribute it should behave this way - enable the default style, replace it, disable theming. Obviously this still isn't modular, if multiple sites do this only one can win, so it still is application level. Also it won't work for controls which don't have a DefaultStyleKey but those are probably considered to be broken anyways (and you already can define the DefaultStyleKey from outside if you really want to, I think)

gix commented 4 years ago

Sounds like https://github.com/dotnet/wpf/issues/110

ericwj commented 4 years ago

As a result, any use of Styles in local application code causes the style to be reverted to Default + Local Style.

Especially if you're not intimately aware of WPF inner workings, this is totally horrible behavior. I spent hours trying to figure out what I was unaware of or was doing wrong. Imho right now styles in general are totally broken.

Seeing that even this looks completely awful I don't imagine this used to work somewhat previously. Haven't tried it on full framework - not going to either.