Control themes
kekekeks opened this issue ยท 14 comments
The current styling system isn't really suitable for defining controls themes:
- we don't have a way to properly specify the default theme
- we don't have a way to completely re-style a control and prevent the current theme selectors from leaking to such re-styled control
So we need a switchable group of styles that can be associated with a control like Style
is associated with one in WPF and basically act like WPF's style.
<Button>
<Button.ControlTheme>
<ControlTheme BasedOn="{x:StaticResource SomeBaseButtonTheme}">
<Setter Property="Background" "Value"="Red"/>
<Style Selector=":pointerover">
<Setter Property="Background" "Value"="Green"/>
</Style>
</ControlTheme>
</Button.ControlTheme>
</Button>
Such control theme could be switched and manipulated by selectors in our regular CSS-like styles.
A control would announce its default theme by implementing
interface IHaveDefaultControlTheme
{
Style GetDefaultControlTheme();
}
which would be generated by the XAML compiler based on x:DefaultControlThemeFor
in a XAML file in the same assembly:
<ControlTheme x:DefaultControlThemeFor="{x:Type MyControl}">
</ControlTheme>
I don't see this functionality on the roadmap and I know you are working to finish up 0.9 at the moment. Can it be assumed this would be targeted for 1.0? As you mentioned in #2981 it would speed up porting of controls which would then open up the floodgate of fixes and new controls coming over from WPF.
Would be nice if used with something like reacts contexts - resource dictionaries are not sufficient because they cannot override parent values iiuc.
Some High level requirements:
- Display Modes
iOS, Windows 10, OSX operating systems Request Light, Dark and HighContrast modes from the application...
Any theme should be able to express:
Default colours (probably Light)
Dark, and HighContrast
If a theme only expresses 1, (it has to be the default) and thats what avalonia falls back to say when HighContrast is asked for.
- Overriding Display Mode
Any Control / Layoutable should be able to say:
Im rendered with Default theme, instead of HighContrast...
This is common for parts of apps that express branding, logos, media, etc
or something way of expressing the same thing.
In UWP they have RequestedTheme property and its an enum with Light / Dark... it seems like UWP is limited to just 2 themes at first... however that is not the case.
because the OS has the concept of Light and Dark that enum expresses that.
A MacOSX theme for UWP is possible, but the theme itself should optionaly define the Default, Dark and High contrast themes
This is an API breaking change as I understand it and in #2239 (comment) it's mentioned 0.11 is going to lock down breaking changes considerably. What happens to this if it doesn't make 0.11? Will it never get implemented?
This is a fundamentally important feature as I see it to the styling system. The current CSS like system is quite powerful but this issue needs to get closed to finish it. (Triggers would be nice too but I suppose behaviors exist for that)
Without this change themes and control styles are more complex than they need to be. We need to wrap each controls default style and template into a single parent container "Style".
@robloo this will get implemented, breaking changes will cause the major revision number to increase by 1.
btw... 0.11 will never be released... the next major version will be 11.0.0
Work was started on this a while ago on https://github.com/AvaloniaUI/Avalonia/commits/feature/2769-control-themes - just needs to be finished off.
In the design of Style, the design of XAML is very bad. It is highly redundant and difficult to read.
I suggest adding support for CSS-3 directly. Use various advanced improvements made to CSS styles in the web(sass,less,scss...) .
I suggest adding support for CSS-3 directly. Use various advanced improvements made to CSS styles in the web(sass,less,scss...) .
GTK eventually went that route too. However, I think you should create a new issue for that.
WPF styling with triggers was pretty intuitive and easy to read. UWP muddied things up a bit for beginners with the VisualStateManager (It also meant hardcoded string states in code-behind which I don't prefer). I'm not a huge fan of pseudoclasses here in Avalonia either but they are more powerful than just triggers on standard properties and work similar in my mind to UWPs VisualStates.
Regardless, XAML styling is fairly straightforward once you get used to it and is far more powerful in Avalonia. The only issue is there is no container for them and you end up with lots of fragments for one control's default style. That is what I hope this issue fixes.
I suggest adding support for CSS-3 directly. Use various advanced improvements made to CSS styles in the web(sass,less,scss...) .
GTK eventually went that route too. However, I think you should create a new issue for that.
Someone has already raised it, and I have already expressed support in this issue.
#3686
As for which one is better,
the shorter the better,
the smaller the number of typing characters, the better,
and the smaller space in view of the same function, the better.
<Style Selector="TabControl">
<Setter Property="Background" Value="#F0F0F0"/>
<Setter Property="Height" Value="120"/>
</Style>
TabControl{
Background:#F0F0F0;
Height:120;
}
I won't argue which one is better. Each has preferences for certain reasons. I will say XAML isn't difficult. This issue is for something different than a full CSS/JSON styling system though.
And more about this specific ticket, why it's not trivial to implement right now.
In proposal XAML compiler should wire default theme with controls in the same assembly. But in reality we don't have (and we shouldn't have) one default theme. User should be able to completely drop old or fluent theme and apply their own. So control shouldn't know about any specific theme, but expect one to be applied. So "IHaveDefaultControlTheme" interface isn't practical.
Stepping back, why we need it at all, is to simplify control restyling.
Easy to imagine situation, where developer included some custom/default theme, which defined many properties and states (pointerover, pressed...) for simple button. But then developer wants to create new independed button style, which will have very special styling. Developer will need to revert all of these styles related to simple button in order to have exactly what they need.
Basically CSS has exactly the same problem for default controls. They have "scoped css" (as we do have scoped styles), but you can't replace these styles with another, without defining new ones on top of old ones (or technically you can remove style include, but...).
And returning to this proposal, as for me I see something like this as a solution:
Define "default" theme for button:
FluentButton.axaml
<ResourceDictionary>
<ControlTheme Type="Button" x:Key="FluentButtonStyle">
<Style Selector="Button">
<Setter Property="Template" Value=" ... " />
</Style>
<Style Selector="Button:pointerover">
<!-- -->
</Style>
</ControlTheme>
</ResourceDictionary>
Apply default theme globally:
FluentThemeDefinitions.axaml
<Styles>
<Style Selector="Button">
<Setter Property="ControlTheme" Value="{StaticResource FluentButtonStyle}" />
</Style>
</Styles>
Develop will be able to completly ignore default theme and implement their own in the same way, OR they can base on it:
MySuperTheme.axaml
<Styles>
<Style Selector="Button">
<Setter Property="ControlTheme">
<ControlTheme Type="Button" BasedOn="{StaticResource FluentButtonStyle}">
<Setter Property="Height" Value="66" />
</ControlTheme>
</Setter>
</Style>
<!-- Or create a new one which will not be based on any other theme -->
<Style Selector="Button.special-button">
<Setter Property="ControlTheme">
<ControlTheme Type="Button">
<Setter Property="Height" Value="22" />
</ControlTheme>
</Setter>
</Style>
<!-- And old style global styles will work too -->
<Style Selector="Button">
<!-- Will be applied to every button -->
</Style>
</Styles>
Questions/problems:
- We probably have to allow any selector inside of ControlTheme, even unrelated to Button, but potentially related to its content. Can we scope it in this way?
- ControlTheme=null must be allowed: avoid breaking changes (there are developers without fluent/default theme) and allow old way styling existed before
- Setting ControlTheme inside of a style essentially modifies application styles while they are executing, which possibly can cause undefined behavior (set control theme inside of another control theme which will set it again to the first theme...hello stack overflow).