Skip to content

Commit 3a455ca

Browse files
committed
* flipper remeasures during flip animation to allow different size contents
* new IsFlippedChanged event
1 parent a4086b1 commit 3a455ca

File tree

6 files changed

+202
-62
lines changed

6 files changed

+202
-62
lines changed

MainDemo.Wpf/Cards.xaml

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@
180180
pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Flipper.xaml
181181
-->
182182
<StackPanel>
183-
<materialDesign:Flipper Style="{StaticResource MaterialDesignCardFlipper}" Margin="4 4 0 0">
183+
<materialDesign:Flipper Style="{StaticResource MaterialDesignCardFlipper}" Margin="4 4 0 0"
184+
IsFlippedChanged="Flipper_OnIsFlippedChanged">
184185
<materialDesign:Flipper.FrontContent>
185186
<Button Style="{StaticResource MaterialDesignFlatButton}"
186187
Command="{x:Static materialDesign:Flipper.FlipCommand}"
@@ -257,5 +258,55 @@
257258
</materialDesign:Flipper.BackContent>
258259
</materialDesign:Flipper>
259260
</StackPanel>
261+
262+
<materialDesign:Flipper Style="{StaticResource MaterialDesignCardFlipper}" Margin="4 4 0 0">
263+
<materialDesign:Flipper.FrontContent>
264+
<Button Style="{StaticResource MaterialDesignFlatButton}"
265+
Command="{x:Static materialDesign:Flipper.FlipCommand}"
266+
Margin="8"
267+
Width="192"
268+
>RESIZING...</Button>
269+
</materialDesign:Flipper.FrontContent>
270+
<materialDesign:Flipper.BackContent>
271+
<Grid Height="256" Width="200">
272+
<Grid.RowDefinitions>
273+
<RowDefinition Height="Auto" />
274+
<RowDefinition Height="*" />
275+
</Grid.RowDefinitions>
276+
<materialDesign:ColorZone Mode="Accent" Padding="6">
277+
<StackPanel Orientation="Horizontal">
278+
<Button Style="{StaticResource MaterialDesignToolForegroundButton}"
279+
Command="{x:Static materialDesign:Flipper.FlipCommand}"
280+
HorizontalAlignment="Left">
281+
<materialDesign:PackIcon Kind="ArrowLeft" HorizontalAlignment="Right" />
282+
</Button>
283+
<TextBlock Margin="8 0 0 0" VerticalAlignment="Center">EDIT USER</TextBlock>
284+
</StackPanel>
285+
</materialDesign:ColorZone>
286+
<Grid Grid.Row="1" Margin="0 6 0 0" HorizontalAlignment="Center" VerticalAlignment="Top"
287+
Width="172">
288+
<Grid.RowDefinitions>
289+
<RowDefinition />
290+
<RowDefinition />
291+
<RowDefinition />
292+
<RowDefinition />
293+
</Grid.RowDefinitions>
294+
<TextBox materialDesign:HintAssist.Hint="First name" materialDesign:HintAssist.IsFloating="True"
295+
Margin="0 12 0 0">James</TextBox>
296+
<TextBox Grid.Row="1" materialDesign:HintAssist.Hint="Last name" materialDesign:HintAssist.IsFloating="True"
297+
Margin="0 12 0 0">Willock</TextBox>
298+
<StackPanel Grid.Row="2" Orientation="Horizontal" Margin="0 12 0 0" HorizontalAlignment="Right">
299+
<TextBlock VerticalAlignment="Center">Email Contact</TextBlock>
300+
<ToggleButton Margin="8 0 0 0"></ToggleButton>
301+
</StackPanel>
302+
<StackPanel Grid.Row="3" Orientation="Horizontal" Margin="0 12 0 0" HorizontalAlignment="Right">
303+
<TextBlock VerticalAlignment="Center">Telephone Contact</TextBlock>
304+
<ToggleButton Margin="8 0 0 0"></ToggleButton>
305+
</StackPanel>
306+
</Grid>
307+
</Grid>
308+
</materialDesign:Flipper.BackContent>
309+
</materialDesign:Flipper>
310+
260311
</WrapPanel>
261312
</UserControl>

MainDemo.Wpf/Cards.xaml.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,10 @@ public Cards()
2424
{
2525
InitializeComponent();
2626
}
27+
28+
private void Flipper_OnIsFlippedChanged(object sender, RoutedPropertyChangedEventArgs<bool> e)
29+
{
30+
System.Diagnostics.Debug.WriteLine("Card is flipped = " + e.NewValue);
31+
}
2732
}
2833
}

MainDemo.Wpf/ProvingGround.xaml

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Button.xaml" />
2323

24+
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Flipper.xaml" />
25+
2426
<!--
2527
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.TextBox.xaml" />
2628
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.TextBlock.xaml" />
@@ -49,23 +51,56 @@
4951
<ColumnDefinition />
5052
<ColumnDefinition />
5153
</Grid.ColumnDefinitions>
52-
53-
<materialDesign:Badged Margin="64" Badge="" x:Name="Counter">
54-
<Button Click="CounterButton_OnClick">MAIL</Button>
55-
</materialDesign:Badged>
56-
57-
<materialDesign:Badged Margin="32" Badge="{materialDesign:PackIcon Kind=Heart}"
58-
BadgeColorZoneMode="Accent"
59-
Grid.Column="1">
60-
<Button>LOVE</Button>
61-
</materialDesign:Badged>
62-
63-
<materialDesign:Badged Margin="32" Badge="DANGER"
64-
BadgeColorZoneMode="Dark"
65-
Grid.Column="2">
66-
<Button>STATUS</Button>
67-
</materialDesign:Badged>
6854

55+
<materialDesign:Flipper Style="{StaticResource MaterialDesignCardFlipper}" Margin="4 4 0 0">
56+
<materialDesign:Flipper.FrontContent>
57+
<Button Style="{StaticResource MaterialDesignFlatButton}"
58+
Command="{x:Static materialDesign:Flipper.FlipCommand}"
59+
Margin="8"
60+
Width="200"
61+
>RESIZING...</Button>
62+
</materialDesign:Flipper.FrontContent>
63+
<materialDesign:Flipper.BackContent>
64+
<Grid Height="256" Width="200">
65+
<Grid.RowDefinitions>
66+
<RowDefinition Height="Auto" />
67+
<RowDefinition Height="*" />
68+
</Grid.RowDefinitions>
69+
<materialDesign:ColorZone Mode="Accent" Padding="6">
70+
<StackPanel Orientation="Horizontal">
71+
<Button Style="{StaticResource MaterialDesignToolForegroundButton}"
72+
Command="{x:Static materialDesign:Flipper.FlipCommand}"
73+
HorizontalAlignment="Left">
74+
<materialDesign:PackIcon Kind="ArrowLeft" HorizontalAlignment="Right" />
75+
</Button>
76+
<TextBlock Margin="8 0 0 0" VerticalAlignment="Center">EDIT USER</TextBlock>
77+
</StackPanel>
78+
</materialDesign:ColorZone>
79+
<Grid Grid.Row="1" Margin="0 6 0 0" HorizontalAlignment="Center" VerticalAlignment="Top"
80+
Width="172">
81+
<Grid.RowDefinitions>
82+
<RowDefinition />
83+
<RowDefinition />
84+
<RowDefinition />
85+
<RowDefinition />
86+
</Grid.RowDefinitions>
87+
<TextBox materialDesign:HintAssist.Hint="First name" materialDesign:HintAssist.IsFloating="True"
88+
Margin="0 12 0 0">James</TextBox>
89+
<TextBox Grid.Row="1" materialDesign:HintAssist.Hint="Last name" materialDesign:HintAssist.IsFloating="True"
90+
Margin="0 12 0 0">Willock</TextBox>
91+
<StackPanel Grid.Row="2" Orientation="Horizontal" Margin="0 12 0 0" HorizontalAlignment="Right">
92+
<TextBlock VerticalAlignment="Center">Email Contact</TextBlock>
93+
<ToggleButton Margin="8 0 0 0"></ToggleButton>
94+
</StackPanel>
95+
<StackPanel Grid.Row="3" Orientation="Horizontal" Margin="0 12 0 0" HorizontalAlignment="Right">
96+
<TextBlock VerticalAlignment="Center">Telephone Contact</TextBlock>
97+
<ToggleButton Margin="8 0 0 0"></ToggleButton>
98+
</StackPanel>
99+
</Grid>
100+
</Grid>
101+
</materialDesign:Flipper.BackContent>
102+
</materialDesign:Flipper>
103+
69104
</Grid>
70105
</UserControl>
71106

MainDemo.Wpf/ProvingGround.xaml.cs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,7 @@ public ProvingGround()
3333
{
3434
SelectedTime = new DateTime(2000, 1, 1, 3, 15, 0)
3535
};
36-
}
37-
38-
private void CounterButton_OnClick(object sender, RoutedEventArgs e)
39-
{
40-
if (Counter.Badge == null || Equals(Counter.Badge, ""))
41-
Counter.Badge = 0;
42-
43-
Counter.Badge = int.Parse(Counter.Badge.ToString()) + 1;
44-
}
36+
}
4537
}
4638

4739
public class ProvingGroundViewModel : INotifyPropertyChanged

MaterialDesignThemes.Wpf/Flipper.cs

Lines changed: 87 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,120 +2,176 @@
22
using System.Windows;
33
using System.Windows.Controls;
44
using System.Windows.Input;
5+
using System.Windows.Threading;
56

67
namespace MaterialDesignThemes.Wpf
78
{
9+
[TemplatePart(Name = Plane3DPartName, Type = typeof(Plane3D))]
810
[TemplateVisualState(GroupName = TemplateFlipGroupName, Name = TemplateFlippedStateName)]
911
[TemplateVisualState(GroupName = TemplateFlipGroupName, Name = TemplateUnflippedStateName)]
1012
public class Flipper : Control
1113
{
1214
public static RoutedCommand FlipCommand = new RoutedCommand();
1315

16+
public const string Plane3DPartName = "PART_Plane3D";
1417
public const string TemplateFlipGroupName = "FlipStates";
1518
public const string TemplateFlippedStateName = "Flipped";
1619
public const string TemplateUnflippedStateName = "Unflipped";
1720

21+
private Plane3D _plane3D;
22+
1823
static Flipper()
1924
{
2025
DefaultStyleKeyProperty.OverrideMetadata(typeof(Flipper), new FrameworkPropertyMetadata(typeof(Flipper)));
2126
}
2227

2328
public Flipper()
2429
{
25-
CommandBindings.Add(new CommandBinding(FlipCommand, FlipHandler));
30+
CommandBindings.Add(new CommandBinding(FlipCommand, FlipHandler));
2631
}
2732

2833
public static readonly DependencyProperty FrontContentProperty = DependencyProperty.Register(
29-
"FrontContent", typeof(object), typeof(Flipper), new PropertyMetadata(default(object)));
34+
nameof(FrontContent), typeof(object), typeof(Flipper), new PropertyMetadata(default(object)));
3035

3136
public object FrontContent
3237
{
33-
get { return (object) GetValue(FrontContentProperty); }
34-
set { SetValue(FrontContentProperty, value); }
38+
get => GetValue(FrontContentProperty);
39+
set => SetValue(FrontContentProperty, value);
3540
}
3641

3742
public static readonly DependencyProperty FrontContentTemplateProperty = DependencyProperty.Register(
38-
"FrontContentTemplate", typeof(DataTemplate), typeof(Flipper), new PropertyMetadata(default(DataTemplate)));
43+
nameof(FrontContentTemplate), typeof(DataTemplate), typeof(Flipper), new PropertyMetadata(default(DataTemplate)));
3944

4045
public DataTemplate FrontContentTemplate
4146
{
42-
get { return (DataTemplate) GetValue(FrontContentTemplateProperty); }
43-
set { SetValue(FrontContentTemplateProperty, value); }
47+
get => (DataTemplate) GetValue(FrontContentTemplateProperty);
48+
set => SetValue(FrontContentTemplateProperty, value);
4449
}
4550

4651
public static readonly DependencyProperty FrontContentTemplateSelectorProperty = DependencyProperty.Register(
47-
"FrontContentTemplateSelector", typeof(DataTemplateSelector), typeof(Flipper), new PropertyMetadata(default(DataTemplateSelector)));
52+
nameof(FrontContentTemplateSelector), typeof(DataTemplateSelector), typeof(Flipper), new PropertyMetadata(default(DataTemplateSelector)));
4853

4954
public DataTemplateSelector FrontContentTemplateSelector
5055
{
51-
get { return (DataTemplateSelector) GetValue(FrontContentTemplateSelectorProperty); }
52-
set { SetValue(FrontContentTemplateSelectorProperty, value); }
56+
get => (DataTemplateSelector) GetValue(FrontContentTemplateSelectorProperty);
57+
set => SetValue(FrontContentTemplateSelectorProperty, value);
5358
}
5459

5560
public static readonly DependencyProperty FrontContentStringFormatProperty = DependencyProperty.Register(
56-
"FrontContentStringFormat", typeof(string), typeof(Flipper), new PropertyMetadata(default(string)));
61+
nameof(FrontContentStringFormat), typeof(string), typeof(Flipper), new PropertyMetadata(default(string)));
5762

5863
public string FrontContentStringFormat
5964
{
60-
get { return (string) GetValue(FrontContentStringFormatProperty); }
61-
set { SetValue(FrontContentStringFormatProperty, value); }
65+
get => (string) GetValue(FrontContentStringFormatProperty);
66+
set => SetValue(FrontContentStringFormatProperty, value);
6267
}
6368

6469
public static readonly DependencyProperty BackContentProperty = DependencyProperty.Register(
65-
"BackContent", typeof(object), typeof(Flipper), new PropertyMetadata(default(object)));
70+
nameof(BackContent), typeof(object), typeof(Flipper), new PropertyMetadata(default(object)));
6671

6772
public object BackContent
6873
{
69-
get { return (object) GetValue(BackContentProperty); }
70-
set { SetValue(BackContentProperty, value); }
74+
get => (object) GetValue(BackContentProperty);
75+
set => SetValue(BackContentProperty, value);
7176
}
7277

7378
public static readonly DependencyProperty BackContentTemplateProperty = DependencyProperty.Register(
74-
"BackContentTemplate", typeof(DataTemplate), typeof(Flipper), new PropertyMetadata(default(DataTemplate)));
79+
nameof(BackContentTemplate), typeof(DataTemplate), typeof(Flipper), new PropertyMetadata(default(DataTemplate)));
7580

7681
public DataTemplate BackContentTemplate
7782
{
78-
get { return (DataTemplate)GetValue(BackContentTemplateProperty); }
79-
set { SetValue(BackContentTemplateProperty, value); }
83+
get => (DataTemplate)GetValue(BackContentTemplateProperty);
84+
set => SetValue(BackContentTemplateProperty, value);
8085
}
8186

8287
public static readonly DependencyProperty BackContentTemplateSelectorProperty = DependencyProperty.Register(
83-
"BackContentTemplateSelector", typeof(DataTemplateSelector), typeof(Flipper), new PropertyMetadata(default(DataTemplateSelector)));
88+
nameof(BackContentTemplateSelector), typeof(DataTemplateSelector), typeof(Flipper), new PropertyMetadata(default(DataTemplateSelector)));
8489

8590
public DataTemplateSelector BackContentTemplateSelector
8691
{
87-
get { return (DataTemplateSelector)GetValue(BackContentTemplateSelectorProperty); }
88-
set { SetValue(BackContentTemplateSelectorProperty, value); }
92+
get => (DataTemplateSelector)GetValue(BackContentTemplateSelectorProperty);
93+
set => SetValue(BackContentTemplateSelectorProperty, value);
8994
}
9095

9196
public static readonly DependencyProperty BackContentStringFormatProperty = DependencyProperty.Register(
92-
"BackContentStringFormat", typeof(string), typeof(Flipper), new PropertyMetadata(default(string)));
97+
nameof(BackContentStringFormat), typeof(string), typeof(Flipper), new PropertyMetadata(default(string)));
9398

9499
public string BackContentStringFormat
95100
{
96-
get { return (string)GetValue(BackContentStringFormatProperty); }
97-
set { SetValue(BackContentStringFormatProperty, value); }
101+
get => (string)GetValue(BackContentStringFormatProperty);
102+
set => SetValue(BackContentStringFormatProperty, value);
98103
}
99104

100105
public static readonly DependencyProperty IsFlippedProperty = DependencyProperty.Register(
101-
"IsFlipped", typeof(bool), typeof(Flipper), new PropertyMetadata(default(bool), FlippedPropertyChangedCallback));
106+
nameof(IsFlipped), typeof(bool), typeof(Flipper), new PropertyMetadata(default(bool), IsFlippedPropertyChangedCallback));
102107

103-
private static void FlippedPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
108+
private static void IsFlippedPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
104109
{
105-
((Flipper)dependencyObject).UpdateVisualStates(true);
106-
}
110+
var flipper = (Flipper)dependencyObject;
111+
flipper.UpdateVisualStates(true);
112+
flipper.RemeasureDuringFlip();
113+
OnIsFlippedChanged(flipper, dependencyPropertyChangedEventArgs);
114+
}
107115

108116
public bool IsFlipped
109117
{
110-
get { return (bool) GetValue(IsFlippedProperty); }
111-
set { SetValue(IsFlippedProperty, value); }
118+
get => (bool) GetValue(IsFlippedProperty);
119+
set => SetValue(IsFlippedProperty, value);
120+
}
121+
122+
public static readonly RoutedEvent IsFlippedChangedEvent =
123+
EventManager.RegisterRoutedEvent(
124+
nameof(IsFlipped),
125+
RoutingStrategy.Bubble,
126+
typeof(RoutedPropertyChangedEventHandler<bool>),
127+
typeof(Flipper));
128+
129+
public event RoutedPropertyChangedEventHandler<bool> IsFlippedChanged
130+
{
131+
add => AddHandler(IsFlippedChangedEvent, value);
132+
remove => RemoveHandler(IsFlippedChangedEvent, value);
133+
}
134+
135+
private static void OnIsFlippedChanged(
136+
DependencyObject d, DependencyPropertyChangedEventArgs e)
137+
{
138+
var instance = (Flipper)d;
139+
var args = new RoutedPropertyChangedEventArgs<bool>(
140+
(bool)e.OldValue,
141+
(bool)e.NewValue)
142+
{ RoutedEvent = IsFlippedChangedEvent };
143+
instance.RaiseEvent(args);
112144
}
113145

114146
public override void OnApplyTemplate()
115147
{
116148
base.OnApplyTemplate();
117149

118150
UpdateVisualStates(false);
151+
152+
_plane3D = GetTemplateChild(Plane3DPartName) as Plane3D;
153+
}
154+
155+
private void RemeasureDuringFlip()
156+
{
157+
//not entirely happy hardcoding this, but I have explored other options I am not happy with, and this will do for now
158+
const int storyboardMs = 400;
159+
const int granularity = 6;
160+
161+
var remeasureInterval = new TimeSpan(0, 0, 0, 0, storyboardMs/granularity);
162+
var refreshCount = 0;
163+
var plane3D = _plane3D;
164+
if (plane3D == null) return;
165+
166+
DispatcherTimer dt = null;
167+
dt = new DispatcherTimer(remeasureInterval, DispatcherPriority.Normal,
168+
(sender, args) =>
169+
{
170+
plane3D.InvalidateMeasure();
171+
if (refreshCount++ == granularity)
172+
dt.Stop();
173+
}, Dispatcher);
174+
dt.Start();
119175
}
120176

121177
private void UpdateVisualStates(bool useTransitions)

0 commit comments

Comments
 (0)