-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ported Fluent Theme to ControlThemes. #8479
Conversation
Name="grid" | ||
Margin="{TemplateBinding Padding}" | ||
RowDefinitions="Auto, *"> | ||
<ContentPresenter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While refactoring, I noticed that this ContentPresenter
doesn't seem to be used. Was it part of a feature that was cut? Can it be removed from the template?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's for Header property that UWP has but we don't. I.e., TextBox.Header, Slider.Header.
It works similarly how our Label works, just built in the template.
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundPressed}" /> | ||
</Style> | ||
|
||
<Style Selector="^[Tag=checked]"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the "tag hack" I mentioned in the description. I'm not happy about it, but it seems to work for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is very ugly... I hope the missing functionality is added so this doesn't become a permanent work-around.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for case, this functionality wasn't removed. You still can use nested /template/
selectors outside of ControlTheme.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, as my luck goes, the places where it would be used (correctly) on my end are in ControlThemes. And I added a larger comment below but if Style still supports this it really seems like ControlTheme should as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can still actually host <Style>
s in the root element of your control theme template in order to use nested template selectors, however I'd try to avoid it if possible.
</Style> | ||
<Style Selector="^:indeterminate"> | ||
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter"> | ||
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundIndeterminate}" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While testing I noticed that the indeterminate state for ToggleButton
looks the same as the unchecked state. Is this intentional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an issue in the toggle switch as well. I had a discussion about this in MahApps back then, The solution was to disallow null
for IsChecked
-property.
See also:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Traditionally (in WPF/WinUI) CheckBox derives from ToggleButton and does make use of the three states. This is very common if a CheckBox is used at the top of a column for example representing each row selection.
Since other controls inherit from ToggleButton, and require three states, I don't think this can or should be removed. It is also just fine for ToggleButton to only consider two states in its style as it can only be toggled on/off by the user.
While testing I noticed that the indeterminate state for ToggleButton looks the same as the unchecked state. Is this intentional?
Yes, this is intentional and matches WinUI. It is only really useful in derived controls like CheckBox.
Source code from UWP Generic.xaml
<!-- Resources for Windows.UI.Xaml.Controls.Primitives.ToggleButton -->
<StaticResource x:Key="ToggleButtonBackground" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundPointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundPressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundChecked" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="ToggleButtonBackgroundCheckedPointerOver" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="ToggleButtonBackgroundCheckedPressed" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundCheckedDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminate" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminatePointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminatePressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminateDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonForegroundChecked" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
<StaticResource x:Key="ToggleButtonForegroundCheckedPointerOver" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
<StaticResource x:Key="ToggleButtonForegroundCheckedPressed" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
<StaticResource x:Key="ToggleButtonForegroundCheckedDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminate" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminatePointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminatePressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminateDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBorderBrush" ResourceKey="SystemControlForegroundTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushPointerOver" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushPressed" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushChecked" ResourceKey="SystemControlHighlightAltTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushCheckedPointerOver" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushCheckedPressed" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushCheckedDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminate" ResourceKey="SystemControlForegroundTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminatePointerOver" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminatePressed" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminateDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
</ControlTheme> | ||
</Style.Resources> | ||
|
||
<Setter Property="Theme" Value="{StaticResource FluentUserControl}" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the moment, the UserControl
theme is being set by a style. We may want to override the effective theme for UserControl
to always return {StaticResource typeof(UserControl)}
when no theme is set explicitly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overriding makes sense to me. Isn't it the same about Window?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Window
is slightly different in that it overrides IStyleable.StyleKey => typeof(Window);
whereas UserControl
doesn't do that due to #2280. It might make sense to use the same technique for both though now.
@@ -125,7 +136,6 @@ | |||
Background="{DynamicResource ComboBoxDropDownBackground}" | |||
BorderBrush="{DynamicResource ComboBoxDropDownBorderBrush}" | |||
BorderThickness="{DynamicResource ComboBoxDropdownBorderThickness}" | |||
Margin="0,-1,0,-1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed this line as it was causing the ComboBox
popup border to be truncated at the top and bottom. I've noticed this for a long time but never investigated it. @danwalmsley you seem to have added this line, do you remember why and it is ok to remove it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is a copy-paste from Fluent v1 in WinUI
That Margin (and any others like it) can safely be removed. It was just a work-around for WinUI/UWP specific issues.
Co-Authored-By: Takoooooo <[email protected]>
Otherwise there's no easy way to apply themes to item containers.
It is more useful if this property inherits by default.
And added "Rounded" option to ControlCatalog for testing.
It was causing the title bar to be shown in all designer previews.
And refactored shared date/time picker components into a separate file.
Not happy with the Tag hack but no better way to add additional states to a control currently.
And tweak some designer previews.
36952df
to
20b2bc2
Compare
Rebased to credit @Takoooooo for the work he did on this. |
When "Rounded" checkbox isn't checked.
<Viewbox> | ||
<Path Stretch="UniformToFill" Fill="{TemplateBinding Foreground}" Data="M2048 1229v-205h-2048v205h2048z" /> | ||
</Button> | ||
<Button x:Name="PART_MinimiseButton" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@danwalmsley I changed these to be buttons, because previously as panels you lost the ability to press and then cancel the press by releasing outside the bounds of the control.
Previously there was a `MenuItem > Separator` selector, but I don't really see any reason to just apply this style directly to `Separator` itself. It's mainly used in menus and if one wants to use it elsewhere then they'd need to set these properties anyway.
I've found other places where directly accessing the template of a control within a template is very useful. Not trying to start another big discussion but if I had a vote I would not want to remove this functionality. It is totally find for one control default style to depend on another control's default style within the same theme (translating to Avalonia's "new terminology" default style = ControlTheme, Theme = FluentTheme). That is a well established convention in XAML styling from the very beginning. Additionally, you are adding code duplication of styles so it would be easy for a button in one control style to be out-of-sync or outdated with the main button's default style. That is an undetectable error -- however, referring to a template part that no longer exists can be detected. So... well, I would not have done this for
|
Yeah we had a pretty intense discussion about this internally as well, but the general consensus was:
So the plan is to:
To give some context: we're currently basically unable to change our templates between major releases because the template contents essentially become a public API due to Given the above we felt that preventing meddling with implementation details of other controls in a new feature is a good start, but removing the feature as it already exists is probably a step too far right now. We are actually open to removing the limitation on nested Does that make sense? |
The problem with this is, how do you define a theme? Are we talking about the fluent theme as defined in |
Started a discussion to discuss the usages of |
You can test this PR using the following package version. |
What does the pull request do?
This PR ports the fluent theme to use
ControlTheme
with @Takoooooo's help.Due to the way that control themes work, some of the themes required a bit of refactoring - in particular we decided not to allow nested
/template/
selectors in control themes, so controls that used these had to have their sub-controls refactored out into separate sub-ControlTheme
s. This is a bit of a pain but should hopefully improve the stability of themes in the long-term as control themes are no longer relying on implementation details of other control themes.The only place the lack of nested
/template/
selectors turned out to really be a problem was inSplitButton
as that control essentially adds additional states toButton
(checked, flyout open). For the moment I've used a hack with setting theTag
property but we really need a proper solution for this - probably something likeClassSetter
which would allow setting classes on controls from a style, or maybe something like the CSS:part
selector (or both).Depends on #7679
Depends on #8263
IMPORTANT
Currently targeting #7679 - change the PR target back to master before merging.