18
18
19
19
namespace MaterialDesignThemes . Wpf
20
20
{
21
- [ TemplatePart ( Name = PartBubbleEllipse , Type = typeof ( Ellipse ) ) ]
21
+ [ TemplateVisualState ( GroupName = "CommonStates" , Name = TemplateStateNormal ) ]
22
+ [ TemplateVisualState ( GroupName = "CommonStates" , Name = TemplateStateMousePressed ) ]
22
23
public class Ripple : ContentControl
23
24
{
24
- public const string PartBubbleEllipse = "PART_BubbleEllipse" ;
25
-
26
- private BubbleStoryboardController _bubbleStoryboardController ;
25
+ public const string TemplateStateNormal = "Normal" ;
26
+ public const string TemplateStateMousePressed = "MousePressed" ;
27
27
28
28
static Ripple ( )
29
29
{
@@ -32,250 +32,111 @@ static Ripple()
32
32
33
33
public Ripple ( )
34
34
{
35
- MouseMove += OnMouseMove ;
36
- }
37
-
38
- protected override void OnPreviewMouseLeftButtonDown ( MouseButtonEventArgs e )
39
- {
40
- var position = e . GetPosition ( this ) ;
41
- MouseLeftButtonDownX = position . X ;
42
- MouseLeftButtonDownY = position . Y ;
43
-
44
- this . ReleaseMouseCapture ( ) ;
45
-
46
- base . OnPreviewMouseLeftButtonDown ( e ) ;
47
- }
48
-
49
- private void OnMouseMove ( object sender , MouseEventArgs mouseEventArgs )
50
- {
51
- var position = mouseEventArgs . GetPosition ( this ) ;
52
- MouseX = position . X ;
53
- MouseY = position . Y ;
54
- }
55
-
56
- public static readonly DependencyProperty IsActiveProperty = DependencyProperty . Register (
57
- "IsActive" , typeof ( bool ) , typeof ( Ripple ) , new FrameworkPropertyMetadata ( false , IsActivePropertyChangedCallback ) ) ;
58
-
59
- public bool IsActive
60
- {
61
- get { return ( bool ) GetValue ( IsActiveProperty ) ; }
62
- set { SetValue ( IsActiveProperty , value ) ; }
35
+ SizeChanged += OnSizeChanged ;
63
36
}
64
37
65
- public override void OnApplyTemplate ( )
38
+ private void OnSizeChanged ( object sender , SizeChangedEventArgs sizeChangedEventArgs )
66
39
{
67
- base . OnApplyTemplate ( ) ;
68
-
69
- _bubbleStoryboardController = new BubbleStoryboardController ( this ) ;
40
+ double radius = Math . Sqrt ( Math . Pow ( sizeChangedEventArgs . NewSize . Width , 2 ) + Math . Pow ( sizeChangedEventArgs . NewSize . Height , 2 ) ) ;
41
+ RippleSize = 2 * radius * RippleSizeMultiplier ;
70
42
}
71
43
72
- private void StartBubbleAnimation ( )
73
- {
74
- _bubbleStoryboardController . Add ( ) ;
75
- }
44
+ public static readonly DependencyProperty FeedbackProperty = DependencyProperty . Register (
45
+ "Feedback" , typeof ( Brush ) , typeof ( Ripple ) , new PropertyMetadata ( default ( Brush ) ) ) ;
76
46
77
- private void StopBubbleAnimation ( )
47
+ public Brush Feedback
78
48
{
79
- _bubbleStoryboardController . Remove ( ) ;
49
+ get { return ( Brush ) GetValue ( FeedbackProperty ) ; }
50
+ set { SetValue ( FeedbackProperty , value ) ; }
80
51
}
81
52
82
- private static void IsActivePropertyChangedCallback (
83
- DependencyObject dependencyObject ,
84
- DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs )
53
+ protected override void OnPreviewMouseLeftButtonDown ( MouseButtonEventArgs e )
85
54
{
86
- var box = dependencyObject as Ripple ;
87
- if ( box == null ) return ;
55
+ var point = e . GetPosition ( this ) ;
88
56
89
- bool isActive = ( bool ) dependencyPropertyChangedEventArgs . NewValue ;
57
+ RippleX = point . X - RippleSize / 2 ;
58
+ RippleY = point . Y - RippleSize / 2 ;
90
59
91
- if ( isActive )
92
- {
93
- box . StartBubbleAnimation ( ) ;
94
- }
95
- else
96
- {
97
- box . StopBubbleAnimation ( ) ;
98
- }
60
+ base . OnPreviewMouseLeftButtonDown ( e ) ;
99
61
}
100
62
101
- public static readonly DependencyProperty FeedbackProperty = DependencyProperty . Register (
102
- "Feedback " , typeof ( Brush ) , typeof ( Ripple ) , new PropertyMetadata ( default ( Brush ) ) ) ;
63
+ public static readonly DependencyProperty RippleSizeMultiplierProperty = DependencyProperty . Register (
64
+ "RippleSizeMultiplier " , typeof ( double ) , typeof ( Ripple ) , new PropertyMetadata ( 1.0 ) ) ;
103
65
104
- public Brush Feedback
66
+ public double RippleSizeMultiplier
105
67
{
106
- get { return ( Brush ) GetValue ( FeedbackProperty ) ; }
107
- set { SetValue ( FeedbackProperty , value ) ; }
68
+ get { return ( double ) GetValue ( RippleSizeMultiplierProperty ) ; }
69
+ set { SetValue ( RippleSizeMultiplierProperty , value ) ; }
108
70
}
109
71
110
- private static readonly DependencyPropertyKey MouseXPropertyKey =
72
+ private static readonly DependencyPropertyKey RippleSizePropertyKey =
111
73
DependencyProperty . RegisterReadOnly (
112
- "MouseX " , typeof ( double ) , typeof ( Ripple ) ,
74
+ "RippleSize " , typeof ( double ) , typeof ( Ripple ) ,
113
75
new PropertyMetadata ( default ( double ) ) ) ;
114
76
115
- public static readonly DependencyProperty MouseXProperty =
116
- MouseXPropertyKey . DependencyProperty ;
77
+ public static readonly DependencyProperty RippleSizeProperty =
78
+ RippleSizePropertyKey . DependencyProperty ;
117
79
118
- public double MouseX
80
+ public double RippleSize
119
81
{
120
- get { return ( double ) GetValue ( MouseXProperty ) ; }
121
- private set { SetValue ( MouseXPropertyKey , value ) ; }
82
+ get { return ( double ) GetValue ( RippleSizeProperty ) ; }
83
+ private set { SetValue ( RippleSizePropertyKey , value ) ; }
122
84
}
123
85
124
- private static readonly DependencyPropertyKey MouseYPropertyKey =
86
+ private static readonly DependencyPropertyKey RippleXPropertyKey =
125
87
DependencyProperty . RegisterReadOnly (
126
- "MouseY " , typeof ( double ) , typeof ( Ripple ) ,
88
+ "RippleX " , typeof ( double ) , typeof ( Ripple ) ,
127
89
new PropertyMetadata ( default ( double ) ) ) ;
128
90
129
- public static readonly DependencyProperty MouseYProperty =
130
- MouseYPropertyKey . DependencyProperty ;
91
+ public static readonly DependencyProperty RippleXProperty =
92
+ RippleXPropertyKey . DependencyProperty ;
131
93
132
- public double MouseY
94
+ public double RippleX
133
95
{
134
- get { return ( double ) GetValue ( MouseYProperty ) ; }
135
- private set { SetValue ( MouseYPropertyKey , value ) ; }
96
+ get { return ( double ) GetValue ( RippleXProperty ) ; }
97
+ private set { SetValue ( RippleXPropertyKey , value ) ; }
136
98
}
137
99
138
- private static readonly DependencyPropertyKey MouseLeftButtonDownXPropertyKey =
100
+ private static readonly DependencyPropertyKey RippleYPropertyKey =
139
101
DependencyProperty . RegisterReadOnly (
140
- "MouseLeftButtonDownX " , typeof ( double ) , typeof ( Ripple ) ,
102
+ "RippleY " , typeof ( double ) , typeof ( Ripple ) ,
141
103
new PropertyMetadata ( default ( double ) ) ) ;
142
104
143
- public static readonly DependencyProperty MouseLeftButtonDownXProperty =
144
- MouseLeftButtonDownXPropertyKey . DependencyProperty ;
105
+ public static readonly DependencyProperty RippleYProperty =
106
+ RippleYPropertyKey . DependencyProperty ;
145
107
146
- public double MouseLeftButtonDownX
108
+ public double RippleY
147
109
{
148
- get { return ( double ) GetValue ( MouseLeftButtonDownXProperty ) ; }
149
- private set { SetValue ( MouseLeftButtonDownXPropertyKey , value ) ; }
110
+ get { return ( double ) GetValue ( RippleYProperty ) ; }
111
+ private set { SetValue ( RippleYPropertyKey , value ) ; }
150
112
}
151
113
152
- private static readonly DependencyPropertyKey MouseLeftButtonDownYPropertyKey =
153
- DependencyProperty . RegisterReadOnly (
154
- "MouseLeftButtonDownY" , typeof ( double ) , typeof ( Ripple ) ,
155
- new PropertyMetadata ( default ( double ) ) ) ;
156
-
157
- public static readonly DependencyProperty MouseLeftButtonDownYProperty =
158
- MouseLeftButtonDownYPropertyKey . DependencyProperty ;
114
+ public static readonly DependencyProperty IsActiveProperty = DependencyProperty . Register (
115
+ "IsActive" , typeof ( bool ) , typeof ( Ripple ) , new FrameworkPropertyMetadata ( false , IsActivePropertyChangedCallback ) ) ;
159
116
160
- public double MouseLeftButtonDownY
117
+ public bool IsActive
161
118
{
162
- get { return ( double ) GetValue ( MouseLeftButtonDownYProperty ) ; }
163
- private set { SetValue ( MouseLeftButtonDownYPropertyKey , value ) ; }
119
+ get { return ( bool ) GetValue ( IsActiveProperty ) ; }
120
+ set { SetValue ( IsActiveProperty , value ) ; }
164
121
}
165
122
166
-
167
- private sealed class BubbleStoryboardController
123
+ private static void IsActivePropertyChangedCallback (
124
+ DependencyObject dependencyObject ,
125
+ DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs )
168
126
{
169
- private readonly Ripple _ripple ;
170
- private readonly Ellipse _ellipse ;
171
- private readonly TimeSpan _fadeOutDuration = TimeSpan . FromMilliseconds ( 200 ) ;
172
- private readonly TimeSpan _bubbleDuration = TimeSpan . FromMilliseconds ( 400 ) ;
173
-
174
- private volatile Storyboard _currentBubbleStoryboard ;
175
- private volatile Storyboard _currentFadeOutStoryboard ;
176
-
177
- public BubbleStoryboardController ( Ripple ripple )
178
- {
179
- _ripple = ripple ;
180
- _ellipse = _ripple . Template . FindName ( PartBubbleEllipse , _ripple ) as Ellipse ;
181
-
182
- if ( _ellipse == null ) throw new InvalidOperationException ( ) ;
183
- }
184
- public void Add ( )
185
- {
186
- _currentFadeOutStoryboard ? . Remove ( ) ;
187
- _currentBubbleStoryboard ? . Remove ( ) ;
188
-
189
- _currentBubbleStoryboard = CreateBubbleStoryboard ( ) ;
190
- _currentBubbleStoryboard . Begin ( ) ;
191
- }
192
-
193
- public void Remove ( )
194
- {
195
- _currentFadeOutStoryboard ? . Remove ( ) ;
196
-
197
- var fadeOutStoryboard = CreateFadeOutStoryboard ( ) ;
198
- var bubbleStoryboardLocalCopy = _currentBubbleStoryboard ;
199
-
200
- fadeOutStoryboard . Completed += delegate
201
- {
202
- fadeOutStoryboard . Remove ( ) ;
203
- bubbleStoryboardLocalCopy ? . Remove ( ) ;
204
- } ;
205
-
206
- _currentFadeOutStoryboard = fadeOutStoryboard ;
207
- _currentFadeOutStoryboard . Begin ( ) ;
208
- }
209
-
210
- private Storyboard CreateFadeOutStoryboard ( )
211
- {
212
- Storyboard resultStorybaord = new Storyboard ( ) ;
213
-
214
- DoubleAnimation opacityAnimation = new DoubleAnimation
215
- {
216
- To = 0
217
- } ;
218
- SetupAnimation ( opacityAnimation , _fadeOutDuration , "(UIElement.Opacity)" ) ;
219
-
220
- resultStorybaord . Children . Add ( opacityAnimation ) ;
221
-
222
- return resultStorybaord ;
223
- }
224
-
225
- private Storyboard CreateBubbleStoryboard ( )
226
- {
227
- Storyboard resultStorybaord = new Storyboard ( ) ;
228
-
229
- DoubleAnimation opacityAnimation = new DoubleAnimation
230
- {
231
- To = 0.26 ,
232
- } ;
233
- SetupAnimation ( opacityAnimation , _bubbleDuration , "(UIElement.Opacity)" ) ;
234
-
235
- double h = Math . Max ( _ripple . MouseLeftButtonDownX , _ripple . ActualWidth - _ripple . MouseLeftButtonDownX ) ;
236
- double w = Math . Max ( _ripple . MouseLeftButtonDownY , _ripple . ActualHeight - _ripple . MouseLeftButtonDownY ) ;
237
- double diameter = 2 * Math . Sqrt ( h * h + w * w ) ;
238
-
239
- DoubleAnimation widthAnimation = new DoubleAnimation
240
- {
241
- To = diameter
242
- } ;
243
- SetupAnimation ( widthAnimation , _bubbleDuration , "(FrameworkElement.Width)" ) ;
244
-
245
- DoubleAnimation heightAnimation = new DoubleAnimation
246
- {
247
- To = diameter
248
- } ;
249
- SetupAnimation ( heightAnimation , _bubbleDuration , "(FrameworkElement.Height)" ) ;
250
-
251
- DoubleAnimation translateXAnimation = new DoubleAnimation
252
- {
253
- To = - diameter / 2
254
- } ;
255
- SetupAnimation ( translateXAnimation , _bubbleDuration , "(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" ) ;
127
+ var box = dependencyObject as Ripple ;
128
+ if ( box == null ) return ;
256
129
257
- DoubleAnimation translateYAnimation = new DoubleAnimation
258
- {
259
- To = - diameter / 2
260
- } ;
261
- SetupAnimation ( translateYAnimation , _bubbleDuration , "(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" ) ;
130
+ bool isActive = ( bool ) dependencyPropertyChangedEventArgs . NewValue ;
262
131
263
- resultStorybaord . Children . Add ( opacityAnimation ) ;
264
- resultStorybaord . Children . Add ( widthAnimation ) ;
265
- resultStorybaord . Children . Add ( heightAnimation ) ;
266
- resultStorybaord . Children . Add ( translateXAnimation ) ;
267
- resultStorybaord . Children . Add ( translateYAnimation ) ;
132
+ VisualStateManager . GoToState ( box , isActive ? TemplateStateMousePressed : TemplateStateNormal , true ) ;
133
+ }
268
134
269
- return resultStorybaord ;
270
- }
135
+ public override void OnApplyTemplate ( )
136
+ {
137
+ base . OnApplyTemplate ( ) ;
271
138
272
- private void SetupAnimation ( AnimationTimeline animation , TimeSpan duration , string propertyPath )
273
- {
274
- animation . AccelerationRatio = 0.25 ;
275
- animation . Duration = new Duration ( duration ) ;
276
- Storyboard . SetTarget ( animation , _ellipse ) ;
277
- Storyboard . SetTargetProperty ( animation , new PropertyPath ( propertyPath ) ) ;
278
- }
139
+ VisualStateManager . GoToState ( this , TemplateStateNormal , false ) ;
279
140
}
280
141
}
281
142
}
0 commit comments