Browse Source

Use nested styles in Button template.

And related fixes to make this work.
pull/8024/head
Steven Kirk 5 years ago
parent
commit
82835ef957
  1. 2
      src/Avalonia.Base/Styling/NestingSelector.cs
  2. 8
      src/Avalonia.Base/Styling/Style.cs
  3. 80
      src/Avalonia.Themes.Fluent/Controls/Button.xaml
  4. 68
      tests/Avalonia.Base.UnitTests/Styling/SelectorTests_Nesting.cs

2
src/Avalonia.Base/Styling/NestingSelector.cs

@ -17,7 +17,7 @@ namespace Avalonia.Styling
{ {
if (parent is Style s && s.Selector is Selector selector) if (parent is Style s && s.Selector is Selector selector)
{ {
return selector.Match(control, null, subscribe); return selector.Match(control, (parent as Style)?.Parent, subscribe);
} }
throw new InvalidOperationException( throw new InvalidOperationException(

8
src/Avalonia.Base/Styling/Style.cs

@ -120,15 +120,19 @@ namespace Avalonia.Styling
instance.Start(); instance.Start();
} }
var result = match.Result;
if (_children is not null) if (_children is not null)
{ {
foreach (var child in _children) foreach (var child in _children)
{ {
child.TryAttach(target, host); var childResult = child.TryAttach(target, host);
if (childResult > result)
result = childResult;
} }
} }
return match.Result; return result;
} }
public bool TryGetResource(object key, out object? result) public bool TryGetResource(object key, out object? result)

80
src/Avalonia.Themes.Fluent/Controls/Button.xaml

@ -7,9 +7,11 @@
</StackPanel> </StackPanel>
</Border> </Border>
</Design.PreviewWith> </Design.PreviewWith>
<Styles.Resources> <Styles.Resources>
<Thickness x:Key="ButtonPadding">8,5,8,6</Thickness> <Thickness x:Key="ButtonPadding">8,5,8,6</Thickness>
</Styles.Resources> </Styles.Resources>
<Style Selector="Button"> <Style Selector="Button">
<Setter Property="Background" Value="{DynamicResource ButtonBackground}" /> <Setter Property="Background" Value="{DynamicResource ButtonBackground}" />
<!--<Setter Property="BackgroundSizing" Value="OuterBorderEdge" />--> <!--<Setter Property="BackgroundSizing" Value="OuterBorderEdge" />-->
@ -37,43 +39,54 @@
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" /> VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
</Style>
<!-- PointerOverState --> <Style.Children>
<Style Selector="Button:pointerover /template/ ContentPresenter#PART_ContentPresenter"> <Style Selector="&amp;:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundPointerOver}" /> <Setter Property="Background" Value="{DynamicResource ButtonBackgroundPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPointerOver}" /> <Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPointerOver}" />
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" /> <Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" />
</Style> </Style>
<Style Selector="Button:pressed /template/ ContentPresenter#PART_ContentPresenter"> <Style Selector="&amp;:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundPressed}" /> <Setter Property="Background" Value="{DynamicResource ButtonBackgroundPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPressed}" /> <Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPressed}" />
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPressed}" /> <Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPressed}" />
</Style> </Style>
<Style Selector="Button:disabled /template/ ContentPresenter#PART_ContentPresenter"> <Style Selector="&amp;:disabled /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" /> <Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}" /> <Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}" />
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundDisabled}" /> <Setter Property="Foreground" Value="{DynamicResource ButtonForegroundDisabled}" />
</Style> </Style>
<Style Selector="Button.accent /template/ ContentPresenter#PART_ContentPresenter"> <Style Selector="&amp;.accent">
<Setter Property="Background" Value="{DynamicResource AccentButtonBackground}" /> <Style.Children>
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrush}" /> <Style Selector="&amp; /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForeground}" /> <Setter Property="Background" Value="{DynamicResource AccentButtonBackground}" />
</Style> <Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrush}" />
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForeground}" />
</Style>
<Style Selector="Button.accent:pointerover /template/ ContentPresenter#PART_ContentPresenter"> <Style Selector="&amp;:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundPointerOver}" /> <Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushPointerOver}" /> <Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushPointerOver}" />
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForegroundPointerOver}" /> <Setter Property="Foreground" Value="{DynamicResource AccentButtonForegroundPointerOver}" />
</Style> </Style>
<Style Selector="Button.accent:pressed /template/ ContentPresenter#PART_ContentPresenter"> <Style Selector="&amp;:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundPressed}" /> <Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushPressed}" /> <Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushPressed}" />
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForegroundPressed}" /> <Setter Property="Foreground" Value="{DynamicResource AccentButtonForegroundPressed}" />
</Style>
<Style Selector="&amp;:disabled /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushDisabled}" />
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForegroundDisabled}" />
</Style>
</Style.Children>
</Style>
</Style.Children>
</Style> </Style>
<Style Selector="Button, RepeatButton, ToggleButton, DropDownButton"> <Style Selector="Button, RepeatButton, ToggleButton, DropDownButton">
@ -89,9 +102,4 @@
<Setter Property="RenderTransform" Value="scale(0.98)" /> <Setter Property="RenderTransform" Value="scale(0.98)" />
</Style> </Style>
<Style Selector="Button.accent:disabled /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushDisabled}" />
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForegroundDisabled}" />
</Style>
</Styles> </Styles>

68
tests/Avalonia.Base.UnitTests/Styling/SelectorTests_Nesting.cs

@ -9,7 +9,7 @@ namespace Avalonia.Base.UnitTests.Styling
public class SelectorTests_Nesting public class SelectorTests_Nesting
{ {
[Fact] [Fact]
public void Nesting_Class_Doesnt_Match_Parent_Selector() public void Nesting_Class_Doesnt_Match_Parent_OfType_Selector()
{ {
var control = new Control2(); var control = new Control2();
Style nested; Style nested;
@ -26,7 +26,7 @@ namespace Avalonia.Base.UnitTests.Styling
} }
[Fact] [Fact]
public void Or_Nesting_Class_Doesnt_Match_Parent_Selector() public void Or_Nesting_Class_Doesnt_Match_Parent_OfType_Selector()
{ {
var control = new Control2(); var control = new Control2();
Style nested; Style nested;
@ -45,7 +45,7 @@ namespace Avalonia.Base.UnitTests.Styling
} }
[Fact] [Fact]
public void Or_Nesting_Child_OfType_Does_Not_Match_Parent_Selector() public void Or_Nesting_Child_OfType_Doesnt_Match_Parent_OfType_Selector()
{ {
var control = new Control1(); var control = new Control1();
var panel = new DockPanel { Children = { control } }; var panel = new DockPanel { Children = { control } };
@ -64,6 +64,34 @@ namespace Avalonia.Base.UnitTests.Styling
Assert.Equal(SelectorMatchResult.NeverThisInstance, match.Result); Assert.Equal(SelectorMatchResult.NeverThisInstance, match.Result);
} }
[Fact]
public void Double_Nesting_Class_Doesnt_Match_Grandparent_OfType_Selector()
{
var control = new Control2
{
Classes = { "foo", "bar" },
};
Style parent;
Style nested;
var grandparent = new Style(x => x.OfType<Control1>())
{
Children =
{
(parent = new Style(x => x.Nesting().Class("foo"))
{
Children =
{
(nested = new Style(x => x.Nesting().Class("bar")))
}
})
}
};
var match = nested.Selector.Match(control, parent);
Assert.Equal(SelectorMatchResult.NeverThisType, match.Result);
}
[Fact] [Fact]
public void Nesting_Class_Matches() public void Nesting_Class_Matches()
{ {
@ -87,6 +115,40 @@ namespace Avalonia.Base.UnitTests.Styling
Assert.False(sink.Active); Assert.False(sink.Active);
} }
[Fact]
public void Double_Nesting_Class_Matches()
{
var control = new Control1
{
Classes = { "foo", "bar" },
};
Style parent;
Style nested;
var grandparent = new Style(x => x.OfType<Control1>())
{
Children =
{
(parent = new Style(x => x.Nesting().Class("foo"))
{
Children =
{
(nested = new Style(x => x.Nesting().Class("bar")))
}
})
}
};
var match = nested.Selector.Match(control, parent);
Assert.Equal(SelectorMatchResult.Sometimes, match.Result);
var sink = new ActivatorSink(match.Activator);
Assert.True(sink.Active);
control.Classes.Remove("foo");
Assert.False(sink.Active);
}
[Fact] [Fact]
public void Or_Nesting_Class_Matches() public void Or_Nesting_Class_Matches()
{ {

Loading…
Cancel
Save