diff --git a/MainDemo.Wpf/Cards.xaml b/MainDemo.Wpf/Cards.xaml
index 067c7ca63e..5eb594ac23 100644
--- a/MainDemo.Wpf/Cards.xaml
+++ b/MainDemo.Wpf/Cards.xaml
@@ -15,6 +15,7 @@
+
@@ -336,36 +337,36 @@
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
@@ -383,13 +384,13 @@
VerticalAlignment="Center">
-
-
+
+
@@ -398,7 +399,7 @@
@@ -443,15 +444,106 @@
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
diff --git a/MainDemo.Wpf/Domain/MainWindowViewModel.cs b/MainDemo.Wpf/Domain/MainWindowViewModel.cs
index 7011b86aca..7cf35cc6d0 100644
--- a/MainDemo.Wpf/Domain/MainWindowViewModel.cs
+++ b/MainDemo.Wpf/Domain/MainWindowViewModel.cs
@@ -247,7 +247,10 @@ private static IEnumerable GenerateDemoItems(ISnackbarMessageQueue sna
DocumentationLink.DemoPageLink(),
DocumentationLink.StyleLink("Card"),
DocumentationLink.ApiLink()
- });
+ })
+ {
+ HorizontalScrollBarVisibilityRequirement = ScrollBarVisibility.Disabled
+ };
yield return new DemoItem(
"Icon Pack",
diff --git a/MainDemo.Wpf/Properties/launchSettings.json b/MainDemo.Wpf/Properties/launchSettings.json
index 3b8cbc0041..aa143eaeea 100644
--- a/MainDemo.Wpf/Properties/launchSettings.json
+++ b/MainDemo.Wpf/Properties/launchSettings.json
@@ -2,7 +2,7 @@
"profiles": {
"Demo App": {
"commandName": "Project",
- "commandLineArgs": "-p Home -t Inherit -f LeftToRight"
+ "commandLineArgs": "-p 3DTest -t Inherit -f LeftToRight"
}
}
}
diff --git a/MaterialDesignThemes.UITests/WPF/Flippers/FlipperTests.cs b/MaterialDesignThemes.UITests/WPF/Flippers/ClassicFlipperTests.cs
similarity index 53%
rename from MaterialDesignThemes.UITests/WPF/Flippers/FlipperTests.cs
rename to MaterialDesignThemes.UITests/WPF/Flippers/ClassicFlipperTests.cs
index 1d33af33c9..b8f771388b 100644
--- a/MaterialDesignThemes.UITests/WPF/Flippers/FlipperTests.cs
+++ b/MaterialDesignThemes.UITests/WPF/Flippers/ClassicFlipperTests.cs
@@ -1,19 +1,21 @@
namespace MaterialDesignThemes.UITests.WPF.Flippers;
-public class FlipperTests : TestBase
+public class ClassicFlipperTests : TestBase
{
- public FlipperTests(ITestOutputHelper output)
+ public ClassicFlipperTests(ITestOutputHelper output)
: base(output)
{ }
[Fact]
- public async Task Flipper_UniformCornerRadiusAndOutlinedCardStyleAttachedPropertiesApplied_AppliesCornerRadiusOnBorder()
+ public async Task UniformCornerRadiusAndOutlinedCardStyleAttachedPropertiesApplied_AppliesCornerRadiusOnBorder()
{
await using var recorder = new TestRecorder(App);
//Arrange
- IVisualElement flipper = await LoadXaml(
- @"");
+ IVisualElement flipper = await LoadXaml(
+ """
+
+ """);
IVisualElement internalCard = await flipper.GetElement();
IVisualElement internalBorder = await internalCard.GetElement();
@@ -30,13 +32,17 @@ public async Task Flipper_UniformCornerRadiusAndOutlinedCardStyleAttachedPropert
}
[Fact]
- public async Task Flipper_UniformCornerRadiusAndElevatedCardStyleAttachedPropertiesApplied_AppliesCornerRadiusOnBorder()
+ public async Task UniformCornerRadiusAndElevatedCardStyleAttachedPropertiesApplied_AppliesCornerRadiusOnBorder()
{
await using var recorder = new TestRecorder(App);
//Arrange
- IVisualElement flipper = await LoadXaml(
- @"");
+ IVisualElement flipper = await LoadXaml(
+ """
+
+ """);
IVisualElement internalCard = await flipper.GetElement();
IVisualElement internalBorder = await internalCard.GetElement();
@@ -53,17 +59,20 @@ public async Task Flipper_UniformCornerRadiusAndElevatedCardStyleAttachedPropert
}
[Fact]
- public async Task Flipper_ElevatedCardStyleApplied_AppliesDefaultElevation()
+ public async Task ElevatedCardStyleApplied_AppliesDefaultElevation()
{
await using var recorder = new TestRecorder(App);
//Arrange
- IVisualElement flipper = await LoadXaml(
- @"");
- IVisualElement internalCard = await flipper.GetElement();
+ IVisualElement flipper = await LoadXaml(
+ """
+
+ """
+ );
+ IVisualElement internalCard = await flipper.GetElement();
//Act
- // TODO: This throws an exception because it fails to load the 'MaterialDesignTheme.Shadows.xaml' resource dictionary in the ElevationAssist static ctor
Elevation? defaultElevation = await internalCard.GetProperty(ElevationAssist.ElevationProperty);
//Assert
diff --git a/MaterialDesignThemes.Wpf/Flipper.cs b/MaterialDesignThemes.Wpf/Flipper.cs
index 3867d219c0..1f01122266 100644
--- a/MaterialDesignThemes.Wpf/Flipper.cs
+++ b/MaterialDesignThemes.Wpf/Flipper.cs
@@ -1,21 +1,15 @@
-using System.Windows.Threading;
+namespace MaterialDesignThemes.Wpf;
-namespace MaterialDesignThemes.Wpf;
-
-[TemplatePart(Name = Plane3DPartName, Type = typeof(Plane3D))]
[TemplateVisualState(GroupName = TemplateFlipGroupName, Name = TemplateFlippedStateName)]
[TemplateVisualState(GroupName = TemplateFlipGroupName, Name = TemplateUnflippedStateName)]
public class Flipper : Control
{
public static readonly RoutedCommand FlipCommand = new();
- public const string Plane3DPartName = "PART_Plane3D";
public const string TemplateFlipGroupName = "FlipStates";
public const string TemplateFlippedStateName = "Flipped";
public const string TemplateUnflippedStateName = "Unflipped";
- private Plane3D? _plane3D;
-
static Flipper()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Flipper), new FrameworkPropertyMetadata(typeof(Flipper)));
@@ -105,7 +99,6 @@ private static void IsFlippedPropertyChangedCallback(DependencyObject dependency
{
var flipper = (Flipper)dependencyObject;
flipper.UpdateVisualStates(true);
- flipper.RemeasureDuringFlip();
OnIsFlippedChanged(flipper, dependencyPropertyChangedEventArgs);
}
@@ -135,7 +128,9 @@ private static void OnIsFlippedChanged(
var args = new RoutedPropertyChangedEventArgs(
(bool)e.OldValue,
(bool)e.NewValue)
- { RoutedEvent = IsFlippedChangedEvent };
+ {
+ RoutedEvent = IsFlippedChangedEvent
+ };
instance.RaiseEvent(args);
}
@@ -144,30 +139,6 @@ public override void OnApplyTemplate()
base.OnApplyTemplate();
UpdateVisualStates(false);
-
- _plane3D = GetTemplateChild(Plane3DPartName) as Plane3D;
- }
-
- private void RemeasureDuringFlip()
- {
- //not entirely happy hardcoding this, but I have explored other options I am not happy with, and this will do for now
- const int storyboardMs = 400;
- const int granularity = 6;
-
- var remeasureInterval = new TimeSpan(0, 0, 0, 0, storyboardMs / granularity);
- var refreshCount = 0;
- var plane3D = _plane3D;
- if (plane3D is null) return;
-
- DispatcherTimer? dt = null;
- dt = new DispatcherTimer(remeasureInterval, DispatcherPriority.Normal,
- (sender, args) =>
- {
- plane3D.InvalidateMeasure();
- if (refreshCount++ == granularity)
- dt?.Stop();
- }, Dispatcher);
- dt.Start();
}
private void UpdateVisualStates(bool useTransitions)
diff --git a/MaterialDesignThemes.Wpf/FlipperClassic.cs b/MaterialDesignThemes.Wpf/FlipperClassic.cs
new file mode 100644
index 0000000000..9269dff206
--- /dev/null
+++ b/MaterialDesignThemes.Wpf/FlipperClassic.cs
@@ -0,0 +1,183 @@
+using System.Windows.Threading;
+
+namespace MaterialDesignThemes.Wpf;
+
+[TemplatePart(Name = Plane3DPartName, Type = typeof(Plane3D))]
+[TemplateVisualState(GroupName = TemplateFlipGroupName, Name = TemplateFlippedStateName)]
+[TemplateVisualState(GroupName = TemplateFlipGroupName, Name = TemplateUnflippedStateName)]
+public class FlipperClassic : Control
+{
+ public static readonly RoutedCommand FlipCommand = new();
+
+ public const string Plane3DPartName = "PART_Plane3D";
+ public const string TemplateFlipGroupName = "FlipStates";
+ public const string TemplateFlippedStateName = "Flipped";
+ public const string TemplateUnflippedStateName = "Unflipped";
+
+ private Plane3D? _plane3D;
+
+ static FlipperClassic()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(FlipperClassic), new FrameworkPropertyMetadata(typeof(FlipperClassic)));
+ }
+
+ public FlipperClassic()
+ {
+ CommandBindings.Add(new CommandBinding(FlipCommand, FlipHandler));
+ }
+
+ public static readonly DependencyProperty FrontContentProperty = DependencyProperty.Register(
+ nameof(FrontContent), typeof(object), typeof(FlipperClassic), new PropertyMetadata(default(object?)));
+
+ public object? FrontContent
+ {
+ get => GetValue(FrontContentProperty);
+ set => SetValue(FrontContentProperty, value);
+ }
+
+ public static readonly DependencyProperty FrontContentTemplateProperty = DependencyProperty.Register(
+ nameof(FrontContentTemplate), typeof(DataTemplate), typeof(FlipperClassic), new PropertyMetadata(default(DataTemplate?)));
+
+ public DataTemplate? FrontContentTemplate
+ {
+ get => (DataTemplate?)GetValue(FrontContentTemplateProperty);
+ set => SetValue(FrontContentTemplateProperty, value);
+ }
+
+ public static readonly DependencyProperty FrontContentTemplateSelectorProperty = DependencyProperty.Register(
+ nameof(FrontContentTemplateSelector), typeof(DataTemplateSelector), typeof(FlipperClassic), new PropertyMetadata(default(DataTemplateSelector)));
+
+ public DataTemplateSelector? FrontContentTemplateSelector
+ {
+ get => (DataTemplateSelector)GetValue(FrontContentTemplateSelectorProperty);
+ set => SetValue(FrontContentTemplateSelectorProperty, value);
+ }
+
+ public static readonly DependencyProperty FrontContentStringFormatProperty = DependencyProperty.Register(
+ nameof(FrontContentStringFormat), typeof(string), typeof(FlipperClassic), new PropertyMetadata(default(string?)));
+
+ public string? FrontContentStringFormat
+ {
+ get => (string?)GetValue(FrontContentStringFormatProperty);
+ set => SetValue(FrontContentStringFormatProperty, value);
+ }
+
+ public static readonly DependencyProperty BackContentProperty = DependencyProperty.Register(
+ nameof(BackContent), typeof(object), typeof(FlipperClassic), new PropertyMetadata(default(object?)));
+
+ public object? BackContent
+ {
+ get => GetValue(BackContentProperty);
+ set => SetValue(BackContentProperty, value);
+ }
+
+ public static readonly DependencyProperty BackContentTemplateProperty = DependencyProperty.Register(
+ nameof(BackContentTemplate), typeof(DataTemplate), typeof(FlipperClassic), new PropertyMetadata(default(DataTemplate?)));
+
+ public DataTemplate? BackContentTemplate
+ {
+ get => (DataTemplate?)GetValue(BackContentTemplateProperty);
+ set => SetValue(BackContentTemplateProperty, value);
+ }
+
+ public static readonly DependencyProperty BackContentTemplateSelectorProperty = DependencyProperty.Register(
+ nameof(BackContentTemplateSelector), typeof(DataTemplateSelector), typeof(FlipperClassic), new PropertyMetadata(default(DataTemplateSelector?)));
+
+ public DataTemplateSelector? BackContentTemplateSelector
+ {
+ get => (DataTemplateSelector?)GetValue(BackContentTemplateSelectorProperty);
+ set => SetValue(BackContentTemplateSelectorProperty, value);
+ }
+
+ public static readonly DependencyProperty BackContentStringFormatProperty = DependencyProperty.Register(
+ nameof(BackContentStringFormat), typeof(string), typeof(FlipperClassic), new PropertyMetadata(default(string?)));
+
+ public string? BackContentStringFormat
+ {
+ get => (string?)GetValue(BackContentStringFormatProperty);
+ set => SetValue(BackContentStringFormatProperty, value);
+ }
+
+ public static readonly DependencyProperty IsFlippedProperty = DependencyProperty.Register(
+ nameof(IsFlipped), typeof(bool), typeof(FlipperClassic), new PropertyMetadata(default(bool), IsFlippedPropertyChangedCallback));
+
+ private static void IsFlippedPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
+ {
+ var flipper = (FlipperClassic)dependencyObject;
+ flipper.UpdateVisualStates(true);
+ flipper.RemeasureDuringFlip();
+ OnIsFlippedChanged(flipper, dependencyPropertyChangedEventArgs);
+ }
+
+ public bool IsFlipped
+ {
+ get => (bool)GetValue(IsFlippedProperty);
+ set => SetValue(IsFlippedProperty, value);
+ }
+
+ public static readonly RoutedEvent IsFlippedChangedEvent =
+ EventManager.RegisterRoutedEvent(
+ nameof(IsFlipped),
+ RoutingStrategy.Bubble,
+ typeof(RoutedPropertyChangedEventHandler),
+ typeof(FlipperClassic));
+
+ public event RoutedPropertyChangedEventHandler IsFlippedChanged
+ {
+ add => AddHandler(IsFlippedChangedEvent, value);
+ remove => RemoveHandler(IsFlippedChangedEvent, value);
+ }
+
+ private static void OnIsFlippedChanged(
+ DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var instance = (FlipperClassic)d;
+ var args = new RoutedPropertyChangedEventArgs(
+ (bool)e.OldValue,
+ (bool)e.NewValue)
+ { RoutedEvent = IsFlippedChangedEvent };
+ instance.RaiseEvent(args);
+ }
+
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ UpdateVisualStates(false);
+
+ _plane3D = GetTemplateChild(Plane3DPartName) as Plane3D;
+ }
+
+ private void RemeasureDuringFlip()
+ {
+ //not entirely happy hardcoding this, but I have explored other options I am not happy with, and this will do for now
+ const int storyboardMs = 400;
+ const int granularity = 6;
+
+ var remeasureInterval = new TimeSpan(0, 0, 0, 0, storyboardMs / granularity);
+ var refreshCount = 0;
+ var plane3D = _plane3D;
+ if (plane3D is null) return;
+
+ DispatcherTimer? dt = null;
+ dt = new DispatcherTimer(remeasureInterval, DispatcherPriority.Normal,
+ (sender, args) =>
+ {
+ plane3D.InvalidateMeasure();
+ if (refreshCount++ == granularity)
+ dt?.Stop();
+ }, Dispatcher);
+ dt.Start();
+ }
+
+ private void UpdateVisualStates(bool useTransitions)
+ {
+ VisualStateManager.GoToState(this, IsFlipped ? TemplateFlippedStateName : TemplateUnflippedStateName,
+ useTransitions);
+ }
+
+ private void FlipHandler(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)
+ {
+ SetCurrentValue(IsFlippedProperty, !IsFlipped);
+ }
+}
diff --git a/MaterialDesignThemes.Wpf/Plane3D.cs b/MaterialDesignThemes.Wpf/Plane3D.cs
index 529c929459..1b588f14c5 100644
--- a/MaterialDesignThemes.Wpf/Plane3D.cs
+++ b/MaterialDesignThemes.Wpf/Plane3D.cs
@@ -142,7 +142,10 @@ private FrameworkElement CreateVisualChild()
Material frontMaterial = new DiffuseMaterial(Brushes.White);
frontMaterial.SetValue(Viewport2DVisual3D.IsVisualHostMaterialProperty, true);
- var vb = new VisualBrush(_logicalChild);
+ var vb = new VisualBrush(_logicalChild)
+ {
+ Stretch = Stretch.None
+ };
SetCachingForObject(vb); // big perf wins by caching!!
Material backMaterial = new DiffuseMaterial(vb);
diff --git a/MaterialDesignThemes.Wpf/Themes/Generic.xaml b/MaterialDesignThemes.Wpf/Themes/Generic.xaml
index f60fbed55a..f28e95da5b 100644
--- a/MaterialDesignThemes.Wpf/Themes/Generic.xaml
+++ b/MaterialDesignThemes.Wpf/Themes/Generic.xaml
@@ -22,6 +22,7 @@
+
diff --git a/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.Flipper.xaml b/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.Flipper.xaml
index 881ac854d1..7247a8db59 100644
--- a/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.Flipper.xaml
+++ b/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.Flipper.xaml
@@ -1,245 +1,141 @@
-
-
-
-
+
diff --git a/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.FlipperClassic.xaml b/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.FlipperClassic.xaml
new file mode 100644
index 0000000000..5e516160a6
--- /dev/null
+++ b/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.FlipperClassic.xaml
@@ -0,0 +1,250 @@
+
+
+
+
+
+
diff --git a/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.ToggleButton.xaml b/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.ToggleButton.xaml
index ed4e951902..22408e98a8 100644
--- a/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.ToggleButton.xaml
+++ b/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.ToggleButton.xaml
@@ -1,7 +1,6 @@