|
2 | 2 | using System.Windows;
|
3 | 3 | using System.Windows.Controls;
|
4 | 4 | using System.Windows.Input;
|
| 5 | +using System.Windows.Threading; |
5 | 6 |
|
6 | 7 | namespace MaterialDesignThemes.Wpf
|
7 | 8 | {
|
| 9 | + [TemplatePart(Name = Plane3DPartName, Type = typeof(Plane3D))] |
8 | 10 | [TemplateVisualState(GroupName = TemplateFlipGroupName, Name = TemplateFlippedStateName)]
|
9 | 11 | [TemplateVisualState(GroupName = TemplateFlipGroupName, Name = TemplateUnflippedStateName)]
|
10 | 12 | public class Flipper : Control
|
11 | 13 | {
|
12 | 14 | public static RoutedCommand FlipCommand = new RoutedCommand();
|
13 | 15 |
|
| 16 | + public const string Plane3DPartName = "PART_Plane3D"; |
14 | 17 | public const string TemplateFlipGroupName = "FlipStates";
|
15 | 18 | public const string TemplateFlippedStateName = "Flipped";
|
16 | 19 | public const string TemplateUnflippedStateName = "Unflipped";
|
17 | 20 |
|
| 21 | + private Plane3D _plane3D; |
| 22 | + |
18 | 23 | static Flipper()
|
19 | 24 | {
|
20 | 25 | DefaultStyleKeyProperty.OverrideMetadata(typeof(Flipper), new FrameworkPropertyMetadata(typeof(Flipper)));
|
21 | 26 | }
|
22 | 27 |
|
23 | 28 | public Flipper()
|
24 | 29 | {
|
25 |
| - CommandBindings.Add(new CommandBinding(FlipCommand, FlipHandler)); |
| 30 | + CommandBindings.Add(new CommandBinding(FlipCommand, FlipHandler)); |
26 | 31 | }
|
27 | 32 |
|
28 | 33 | 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))); |
30 | 35 |
|
31 | 36 | public object FrontContent
|
32 | 37 | {
|
33 |
| - get { return (object) GetValue(FrontContentProperty); } |
34 |
| - set { SetValue(FrontContentProperty, value); } |
| 38 | + get => GetValue(FrontContentProperty); |
| 39 | + set => SetValue(FrontContentProperty, value); |
35 | 40 | }
|
36 | 41 |
|
37 | 42 | 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))); |
39 | 44 |
|
40 | 45 | public DataTemplate FrontContentTemplate
|
41 | 46 | {
|
42 |
| - get { return (DataTemplate) GetValue(FrontContentTemplateProperty); } |
43 |
| - set { SetValue(FrontContentTemplateProperty, value); } |
| 47 | + get => (DataTemplate) GetValue(FrontContentTemplateProperty); |
| 48 | + set => SetValue(FrontContentTemplateProperty, value); |
44 | 49 | }
|
45 | 50 |
|
46 | 51 | 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))); |
48 | 53 |
|
49 | 54 | public DataTemplateSelector FrontContentTemplateSelector
|
50 | 55 | {
|
51 |
| - get { return (DataTemplateSelector) GetValue(FrontContentTemplateSelectorProperty); } |
52 |
| - set { SetValue(FrontContentTemplateSelectorProperty, value); } |
| 56 | + get => (DataTemplateSelector) GetValue(FrontContentTemplateSelectorProperty); |
| 57 | + set => SetValue(FrontContentTemplateSelectorProperty, value); |
53 | 58 | }
|
54 | 59 |
|
55 | 60 | 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))); |
57 | 62 |
|
58 | 63 | public string FrontContentStringFormat
|
59 | 64 | {
|
60 |
| - get { return (string) GetValue(FrontContentStringFormatProperty); } |
61 |
| - set { SetValue(FrontContentStringFormatProperty, value); } |
| 65 | + get => (string) GetValue(FrontContentStringFormatProperty); |
| 66 | + set => SetValue(FrontContentStringFormatProperty, value); |
62 | 67 | }
|
63 | 68 |
|
64 | 69 | 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))); |
66 | 71 |
|
67 | 72 | public object BackContent
|
68 | 73 | {
|
69 |
| - get { return (object) GetValue(BackContentProperty); } |
70 |
| - set { SetValue(BackContentProperty, value); } |
| 74 | + get => (object) GetValue(BackContentProperty); |
| 75 | + set => SetValue(BackContentProperty, value); |
71 | 76 | }
|
72 | 77 |
|
73 | 78 | 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))); |
75 | 80 |
|
76 | 81 | public DataTemplate BackContentTemplate
|
77 | 82 | {
|
78 |
| - get { return (DataTemplate)GetValue(BackContentTemplateProperty); } |
79 |
| - set { SetValue(BackContentTemplateProperty, value); } |
| 83 | + get => (DataTemplate)GetValue(BackContentTemplateProperty); |
| 84 | + set => SetValue(BackContentTemplateProperty, value); |
80 | 85 | }
|
81 | 86 |
|
82 | 87 | 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))); |
84 | 89 |
|
85 | 90 | public DataTemplateSelector BackContentTemplateSelector
|
86 | 91 | {
|
87 |
| - get { return (DataTemplateSelector)GetValue(BackContentTemplateSelectorProperty); } |
88 |
| - set { SetValue(BackContentTemplateSelectorProperty, value); } |
| 92 | + get => (DataTemplateSelector)GetValue(BackContentTemplateSelectorProperty); |
| 93 | + set => SetValue(BackContentTemplateSelectorProperty, value); |
89 | 94 | }
|
90 | 95 |
|
91 | 96 | 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))); |
93 | 98 |
|
94 | 99 | public string BackContentStringFormat
|
95 | 100 | {
|
96 |
| - get { return (string)GetValue(BackContentStringFormatProperty); } |
97 |
| - set { SetValue(BackContentStringFormatProperty, value); } |
| 101 | + get => (string)GetValue(BackContentStringFormatProperty); |
| 102 | + set => SetValue(BackContentStringFormatProperty, value); |
98 | 103 | }
|
99 | 104 |
|
100 | 105 | 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)); |
102 | 107 |
|
103 |
| - private static void FlippedPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) |
| 108 | + private static void IsFlippedPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) |
104 | 109 | {
|
105 |
| - ((Flipper)dependencyObject).UpdateVisualStates(true); |
106 |
| - } |
| 110 | + var flipper = (Flipper)dependencyObject; |
| 111 | + flipper.UpdateVisualStates(true); |
| 112 | + flipper.RemeasureDuringFlip(); |
| 113 | + OnIsFlippedChanged(flipper, dependencyPropertyChangedEventArgs); |
| 114 | + } |
107 | 115 |
|
108 | 116 | public bool IsFlipped
|
109 | 117 | {
|
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); |
112 | 144 | }
|
113 | 145 |
|
114 | 146 | public override void OnApplyTemplate()
|
115 | 147 | {
|
116 | 148 | base.OnApplyTemplate();
|
117 | 149 |
|
118 | 150 | 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(); |
119 | 175 | }
|
120 | 176 |
|
121 | 177 | private void UpdateVisualStates(bool useTransitions)
|
|
0 commit comments