Skip to content

Commit

Permalink
Refactor fix for 2689 to use attached properties (#2762)
Browse files Browse the repository at this point in the history
* Refactor fix for 2689 to use attached properties

Added attached properties for UniformCornerRadius and Style. These properties are inherited and can thus be used to manipulate a Card located inside of another UIElement (eg. the Flipper).

* Make CardAssist.CardStyle lenient towards unaccepted style

Fallback to default(Style) if the TargetType is not Card.

* Renamed CardAssist and improved guard in CardStyle setter (of attached property)

You mentioned on stream that fact that derived types would not work for the CardStyle because of the guard which is completely correct. So I loosened up the requirements by using IsAssignableFrom() instead.

* Fixed broken Flipper (UI) tests

Rename operation did not pick up the string literal in these tests
  • Loading branch information
nicolaihenriksen authored Jul 8, 2022
1 parent 8578fba commit 78c4aa3
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 16 deletions.
32 changes: 30 additions & 2 deletions MainDemo.Wpf/Cards.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -649,14 +649,42 @@
<materialDesign:Flipper
Style="{StaticResource MaterialDesignCardFlipper}"
IsFlippedChanged="Flipper_OnIsFlippedChanged"
UniformCornerRadius="8">
materialDesign:FlipperAssist.UniformCornerRadius="8">
<materialDesign:Flipper.FrontContent>
<Button
Style="{StaticResource MaterialDesignFlatButton}"
Command="{x:Static materialDesign:Flipper.FlipCommand}"
Margin="8"
Width="184"
Content="Rounded Card Flipper"/>
Content="Rounded Card Flipper 1"/>
</materialDesign:Flipper.FrontContent>
<materialDesign:Flipper.BackContent>
<Button
Style="{StaticResource MaterialDesignFlatButton}"
Command="{x:Static materialDesign:Flipper.FlipCommand}"
Margin="8"
Width="184"
Content="GO BACK"/>
</materialDesign:Flipper.BackContent>
</materialDesign:Flipper>
</smtx:XamlDisplay>

<smtx:XamlDisplay
UniqueKey="cards_12"
Margin="4 4 0 0"
VerticalContentAlignment="Top">
<materialDesign:Flipper
Style="{StaticResource MaterialDesignCardFlipper}"
IsFlippedChanged="Flipper_OnIsFlippedChanged"
materialDesign:FlipperAssist.UniformCornerRadius="8"
materialDesign:FlipperAssist.CardStyle="{StaticResource MaterialDesignOutlinedCard}">
<materialDesign:Flipper.FrontContent>
<Button
Style="{StaticResource MaterialDesignFlatButton}"
Command="{x:Static materialDesign:Flipper.FlipCommand}"
Margin="8"
Width="184"
Content="Rounded Card Flipper 2"/>
</materialDesign:Flipper.FrontContent>
<materialDesign:Flipper.BackContent>
<Button
Expand Down
30 changes: 30 additions & 0 deletions MaterialDesignThemes.UITests/WPF/Cards/ElevatedCardTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
namespace MaterialDesignThemes.UITests.WPF.Cards;

public class ElevatedCardTests : TestBase
{
public ElevatedCardTests(ITestOutputHelper output)
: base(output)
{ }

[Fact]
public async Task ElevatedCard_UniformCornerRadiusApplied_AppliesCornerRadiusOnBorder()
{
await using var recorder = new TestRecorder(App);

//Arrange
IVisualElement<Card> card = await LoadXaml<Card>(
@"<materialDesign:Card Content=""Hello World"" Style=""{StaticResource MaterialDesignElevatedCard}"" UniformCornerRadius=""5"" />");
IVisualElement<Border> internalBorder = await card.GetElement<Border>();

//Act
CornerRadius? internalBorderCornerRadius = await internalBorder.GetCornerRadius();

//Assert
Assert.Equal(5, internalBorderCornerRadius.Value.TopLeft);
Assert.Equal(5, internalBorderCornerRadius.Value.TopRight);
Assert.Equal(5, internalBorderCornerRadius.Value.BottomRight);
Assert.Equal(5, internalBorderCornerRadius.Value.BottomLeft);

recorder.Success();
}
}
54 changes: 54 additions & 0 deletions MaterialDesignThemes.UITests/WPF/Flippers/FlipperTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
namespace MaterialDesignThemes.UITests.WPF.Flippers;

public class FlipperTests : TestBase
{
public FlipperTests(ITestOutputHelper output)
: base(output)
{ }

[Fact]
public async Task Flipper_UniformCornerRadiusAndOutlinedCardStyleAttachedPropertiesApplied_AppliesCornerRadiusOnBorder()
{
await using var recorder = new TestRecorder(App);

//Arrange
IVisualElement<Flipper> flipper = await LoadXaml<Flipper>(
@"<materialDesign:Flipper Style=""{StaticResource MaterialDesignCardFlipper}"" materialDesign:FlipperAssist.CardStyle=""{StaticResource MaterialDesignOutlinedCard}"" materialDesign:FlipperAssist.UniformCornerRadius=""5"" />");
IVisualElement<Card> internalCard = await flipper.GetElement<Card>();
IVisualElement<Border> internalBorder = await internalCard.GetElement<Border>();

//Act
CornerRadius? internalBorderCornerRadius = await internalBorder.GetCornerRadius();

//Assert
Assert.Equal(5, internalBorderCornerRadius.Value.TopLeft);
Assert.Equal(5, internalBorderCornerRadius.Value.TopRight);
Assert.Equal(5, internalBorderCornerRadius.Value.BottomRight);
Assert.Equal(5, internalBorderCornerRadius.Value.BottomLeft);

recorder.Success();
}

[Fact]
public async Task Flipper_UniformCornerRadiusAndElevatedCardStyleAttachedPropertiesApplied_AppliesCornerRadiusOnBorder()
{
await using var recorder = new TestRecorder(App);

//Arrange
IVisualElement<Flipper> flipper = await LoadXaml<Flipper>(
@"<materialDesign:Flipper Style=""{StaticResource MaterialDesignCardFlipper}"" materialDesign:FlipperAssist.CardStyle=""{StaticResource MaterialDesignElevatedCard}"" materialDesign:FlipperAssist.UniformCornerRadius=""5"" />");
IVisualElement<Card> internalCard = await flipper.GetElement<Card>();
IVisualElement<Border> internalBorder = await internalCard.GetElement<Border>();

//Act
CornerRadius? internalBorderCornerRadius = await internalBorder.GetCornerRadius();

//Assert
Assert.Equal(5, internalBorderCornerRadius.Value.TopLeft);
Assert.Equal(5, internalBorderCornerRadius.Value.TopRight);
Assert.Equal(5, internalBorderCornerRadius.Value.BottomRight);
Assert.Equal(5, internalBorderCornerRadius.Value.BottomLeft);

recorder.Success();
}
}
61 changes: 61 additions & 0 deletions MaterialDesignThemes.Wpf.Tests/FlipperAssistTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using Xunit;

namespace MaterialDesignThemes.Wpf.Tests;

public class FlipperAssistTests
{
private readonly FrameworkElement _testElement;

public FlipperAssistTests()
{
_testElement = new FrameworkElement();
}

[StaFact]
public void CardStyle_CardStyleNotSet_AttachedPropertyNotSet()
{
// Assert
Assert.Null(FlipperAssist.GetCardStyle(_testElement));
}

[StaFact]
public void CardStyle_StyleWithWrongTargetType_AttachedPropertyNotSet()
{
// Arrange
var style = new Style(typeof(Button));

// Act
FlipperAssist.SetCardStyle(_testElement, style);

// Assert
Assert.Null(FlipperAssist.GetCardStyle(_testElement));
}

[StaFact]
public void CardStyle_StyleWithCorrectTargetType_AttachedPropertySet()
{
// Arrange
var style = new Style(typeof(Card));

// Act
FlipperAssist.SetCardStyle(_testElement, style);

// Assert
Assert.Equal(style, FlipperAssist.GetCardStyle(_testElement));
}

[StaFact]
public void CardStyle_StyleWithDerivedCardTargetType_AttachedPropertySet()
{
// Arrange
var style = new Style(typeof(DerivedCard));

// Act
FlipperAssist.SetCardStyle(_testElement, style);

// Assert
Assert.Equal(style, FlipperAssist.GetCardStyle(_testElement));
}

internal class DerivedCard : Card { }
}
12 changes: 0 additions & 12 deletions MaterialDesignThemes.Wpf/Flipper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,18 +143,6 @@ private static void OnIsFlippedChanged(
instance.RaiseEvent(args);
}

public static readonly DependencyProperty UniformCornerRadiusProperty = DependencyProperty.Register(
nameof(UniformCornerRadius), typeof(double), typeof(Flipper), new PropertyMetadata(default(double)));

/// <summary>
/// Gets or sets the (uniform) corner radius applied the the <see cref="Flipper"/> when the MaterialDesignCardFlipper style is applied.
/// </summary>
public double UniformCornerRadius
{
get => (double)GetValue(UniformCornerRadiusProperty);
set => SetValue(UniformCornerRadiusProperty, value);
}

public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Expand Down
34 changes: 34 additions & 0 deletions MaterialDesignThemes.Wpf/FlipperAssist.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
namespace MaterialDesignThemes.Wpf;

public static class FlipperAssist
{
#region AttachedProperty : UniformCornerRadiusProperty
/// <summary>
/// Controls the (uniform) corner radius of the contained card
/// </summary>
public static readonly DependencyProperty UniformCornerRadiusProperty
= DependencyProperty.RegisterAttached("UniformCornerRadius", typeof(double), typeof(FlipperAssist),
new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits));

public static void SetUniformCornerRadius(DependencyObject element, double value) => element.SetValue(UniformCornerRadiusProperty, value);
public static double GetUniformCornerRadius(DependencyObject element) => (double)element.GetValue(UniformCornerRadiusProperty);
#endregion

#region AttachedProperty : CardStyleProperty
/// <summary>
/// Controls the style of the contained card
/// </summary>
public static readonly DependencyProperty CardStyleProperty
= DependencyProperty.RegisterAttached("CardStyle", typeof(Style), typeof(FlipperAssist),
new FrameworkPropertyMetadata(default(Style), FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits, null, CoerceCardStyleCallback));
private static object? CoerceCardStyleCallback(DependencyObject d, object baseValue)
{
if (baseValue is Style style && !typeof(Card).IsAssignableFrom(style.TargetType))
return default(Style);
return baseValue;
}

public static void SetCardStyle(DependencyObject element, Style value) => element.SetValue(CardStyleProperty, value);
public static Style GetCardStyle(DependencyObject element) => (Style)element.GetValue(CardStyleProperty);
#endregion
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
</MultiBinding>
</AdornerDecorator.OpacityMask>
<Border Effect="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(wpf:ShadowAssist.ShadowDepth), Converter={x:Static converters:ShadowConverter.Instance}}"
CornerRadius="{TemplateBinding UniformCornerRadius}">
CornerRadius="{TemplateBinding UniformCornerRadius, Converter={x:Static converters:DoubleToCornerRadiusConverter.Instance}}">
<Border Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}"
x:Name="PART_ClipBorder"
Clip="{TemplateBinding ContentClip}" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,9 @@
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<wpf:Plane3D x:Name="PART_Plane3D" RotationY="0" ZFactor="2.055">
<wpf:Card wpf:ShadowAssist.ShadowDepth="{TemplateBinding wpf:ShadowAssist.ShadowDepth}" UniformCornerRadius="{TemplateBinding UniformCornerRadius}">
<wpf:Card wpf:ShadowAssist.ShadowDepth="{TemplateBinding wpf:ShadowAssist.ShadowDepth}"
UniformCornerRadius="{TemplateBinding wpf:FlipperAssist.UniformCornerRadius}"
Style="{TemplateBinding wpf:FlipperAssist.CardStyle}">
<Grid>
<ContentPresenter x:Name="FrontContentPresenter"
Margin="{TemplateBinding Padding}"
Expand Down

0 comments on commit 78c4aa3

Please sign in to comment.