1
+ using System ;
2
+ using System . Collections . Generic ;
3
+ using System . Linq ;
4
+ using System . Windows ;
5
+ using System . Windows . Controls ;
6
+ using System . Windows . Controls . Primitives ;
7
+ using System . Windows . Input ;
8
+
9
+ namespace MaterialDesignThemes . Wpf . Transitions
10
+ {
11
+ /// <summary>
12
+ /// The transitioner provides an easy way to move between content with a default in-place circular transition.
13
+ /// </summary>
14
+ public class Transitioner : Selector , IZIndexController
15
+ {
16
+ private Point ? _nextTransitionOrigin ;
17
+
18
+ static Transitioner ( )
19
+ {
20
+ DefaultStyleKeyProperty . OverrideMetadata ( typeof ( Transitioner ) , new FrameworkPropertyMetadata ( typeof ( Transitioner ) ) ) ;
21
+ }
22
+
23
+ /// <summary>
24
+ /// Causes the the next slide to be displayed (affectively increments <see cref="SelectedIndex"/>).
25
+ /// </summary>
26
+ public static RoutedCommand MoveNextCommand = new RoutedCommand ( ) ;
27
+
28
+ /// <summary>
29
+ /// Causes the the previous slide to be displayed (affectively decrements <see cref="SelectedIndex"/>).
30
+ /// </summary>
31
+ public static RoutedCommand MovePreviousCommand = new RoutedCommand ( ) ;
32
+
33
+ /// <summary>
34
+ /// Moves to the first slide.
35
+ /// </summary>
36
+ public static RoutedCommand MoveFirstCommand = new RoutedCommand ( ) ;
37
+
38
+ /// <summary>
39
+ /// Moves to the last slide.
40
+ /// </summary>
41
+ public static RoutedCommand MoveLastCommand = new RoutedCommand ( ) ;
42
+
43
+ public static readonly DependencyProperty AutoApplyTransitionOriginsProperty = DependencyProperty . Register (
44
+ "AutoApplyTransitionOrigins" , typeof ( bool ) , typeof ( Transitioner ) , new PropertyMetadata ( default ( bool ) ) ) ;
45
+
46
+ public bool AutoApplyTransitionOrigins
47
+ {
48
+ get { return ( bool ) GetValue ( AutoApplyTransitionOriginsProperty ) ; }
49
+ set { SetValue ( AutoApplyTransitionOriginsProperty , value ) ; }
50
+ }
51
+
52
+ public Transitioner ( )
53
+ {
54
+ CommandBindings . Add ( new CommandBinding ( MoveNextCommand , MoveNextHandler ) ) ;
55
+ CommandBindings . Add ( new CommandBinding ( MovePreviousCommand , MovePreviousHandler ) ) ;
56
+ CommandBindings . Add ( new CommandBinding ( MoveFirstCommand , MoveFirstHandler ) ) ;
57
+ CommandBindings . Add ( new CommandBinding ( MoveLastCommand , MoveLastHandler ) ) ;
58
+ AddHandler ( TransitionerSlide . InTransitionFinished , new RoutedEventHandler ( IsTransitionFinishedHandler ) ) ;
59
+ Loaded += ( sender , args ) =>
60
+ {
61
+ if ( SelectedIndex != - 1 )
62
+ ActivateFrame ( SelectedIndex , - 1 ) ;
63
+ } ;
64
+ }
65
+
66
+ protected override bool IsItemItsOwnContainerOverride ( object item )
67
+ {
68
+ return item is TransitionerSlide ;
69
+ }
70
+
71
+ protected override DependencyObject GetContainerForItemOverride ( )
72
+ {
73
+ return new TransitionerSlide ( ) ;
74
+ }
75
+
76
+ protected override void OnPreviewMouseLeftButtonDown ( MouseButtonEventArgs e )
77
+ {
78
+ if ( AutoApplyTransitionOrigins )
79
+ _nextTransitionOrigin = GetNavigationSourcePoint ( e ) ;
80
+ base . OnPreviewMouseLeftButtonDown ( e ) ;
81
+ }
82
+
83
+ protected override void OnSelectionChanged ( SelectionChangedEventArgs e )
84
+ {
85
+ var unselectedIndex = - 1 ;
86
+ if ( e . RemovedItems . Count == 1 )
87
+ {
88
+ unselectedIndex = Items . IndexOf ( e . RemovedItems [ 0 ] ) ;
89
+ }
90
+ var selectedIndex = 1 ;
91
+ if ( e . AddedItems . Count == 1 )
92
+ {
93
+ selectedIndex = Items . IndexOf ( e . AddedItems [ 0 ] ) ;
94
+ }
95
+
96
+ ActivateFrame ( selectedIndex , unselectedIndex ) ;
97
+
98
+ base . OnSelectionChanged ( e ) ;
99
+ }
100
+
101
+ private void IsTransitionFinishedHandler ( object sender , RoutedEventArgs routedEventArgs )
102
+ {
103
+ foreach ( var slide in Items . OfType < object > ( ) . Select ( GetSlide ) . Where ( s => s . State == TransitionerSlideState . Previous ) )
104
+ {
105
+ slide . SetCurrentValue ( TransitionerSlide . StateProperty , TransitionerSlideState . None ) ;
106
+ }
107
+ }
108
+
109
+ private void MoveNextHandler ( object sender , ExecutedRoutedEventArgs executedRoutedEventArgs )
110
+ {
111
+ _nextTransitionOrigin = GetNavigationSourcePoint ( executedRoutedEventArgs ) ;
112
+ SetCurrentValue ( SelectedIndexProperty , Math . Min ( Items . Count - 1 , SelectedIndex + 1 ) ) ;
113
+ }
114
+
115
+ private void MovePreviousHandler ( object sender , ExecutedRoutedEventArgs executedRoutedEventArgs )
116
+ {
117
+ _nextTransitionOrigin = GetNavigationSourcePoint ( executedRoutedEventArgs ) ;
118
+ SetCurrentValue ( SelectedIndexProperty , Math . Max ( 0 , SelectedIndex - 1 ) ) ;
119
+ }
120
+
121
+ private void MoveFirstHandler ( object sender , ExecutedRoutedEventArgs executedRoutedEventArgs )
122
+ {
123
+ _nextTransitionOrigin = GetNavigationSourcePoint ( executedRoutedEventArgs ) ;
124
+ SetCurrentValue ( SelectedIndexProperty , 0 ) ;
125
+ }
126
+
127
+ private void MoveLastHandler ( object sender , ExecutedRoutedEventArgs executedRoutedEventArgs )
128
+ {
129
+ _nextTransitionOrigin = GetNavigationSourcePoint ( executedRoutedEventArgs ) ;
130
+ SetCurrentValue ( SelectedIndexProperty , Items . Count - 1 ) ;
131
+ }
132
+
133
+ private Point ? GetNavigationSourcePoint ( RoutedEventArgs executedRoutedEventArgs )
134
+ {
135
+ var sourceElement = executedRoutedEventArgs . OriginalSource as FrameworkElement ;
136
+ if ( sourceElement == null || ! IsAncestorOf ( sourceElement ) || ! IsSafePositive ( ActualWidth ) ||
137
+ ! IsSafePositive ( ActualHeight ) || ! IsSafePositive ( sourceElement . ActualWidth ) ||
138
+ ! IsSafePositive ( sourceElement . ActualHeight ) ) return null ;
139
+
140
+ var transitionOrigin = sourceElement . TranslatePoint ( new Point ( sourceElement . ActualWidth / 2 , sourceElement . ActualHeight ) , this ) ;
141
+ transitionOrigin = new Point ( transitionOrigin . X / ActualWidth , transitionOrigin . Y / ActualHeight ) ;
142
+ return transitionOrigin ;
143
+ }
144
+
145
+ private static bool IsSafePositive ( double dubz )
146
+ {
147
+ return ! double . IsNaN ( dubz ) && ! double . IsInfinity ( dubz ) && dubz > 0.0 ;
148
+ }
149
+
150
+ private TransitionerSlide GetSlide ( object item )
151
+ {
152
+ if ( IsItemItsOwnContainer ( item ) )
153
+ return ( TransitionerSlide ) item ;
154
+
155
+ return ( TransitionerSlide ) ItemContainerGenerator . ContainerFromItem ( item ) ;
156
+ }
157
+
158
+ private void ActivateFrame ( int selectedIndex , int unselectedIndex )
159
+ {
160
+ if ( ! IsLoaded ) return ;
161
+
162
+ TransitionerSlide oldSlide = null , newSlide = null ;
163
+ for ( var index = 0 ; index < Items . Count ; index ++ )
164
+ {
165
+ var slide = GetSlide ( Items [ index ] ) ;
166
+ if ( index == selectedIndex )
167
+ {
168
+ newSlide = slide ;
169
+ slide . SetCurrentValue ( TransitionerSlide . StateProperty , TransitionerSlideState . Current ) ;
170
+ }
171
+ else if ( index == unselectedIndex )
172
+ {
173
+ oldSlide = slide ;
174
+ slide . SetCurrentValue ( TransitionerSlide . StateProperty , TransitionerSlideState . Previous ) ;
175
+ }
176
+ else
177
+ {
178
+ slide . SetCurrentValue ( TransitionerSlide . StateProperty , TransitionerSlideState . None ) ;
179
+ }
180
+ Panel . SetZIndex ( slide , 0 ) ;
181
+ }
182
+
183
+ if ( newSlide != null )
184
+ newSlide . Opacity = 1 ;
185
+
186
+ if ( oldSlide != null && newSlide != null )
187
+ {
188
+ var wipe = selectedIndex > unselectedIndex ? oldSlide . ForwardWipe : oldSlide . BackwardWipe ;
189
+ if ( wipe != null )
190
+ wipe . Wipe ( oldSlide , newSlide , _nextTransitionOrigin ?? new Point ( .5 , .5 ) , this ) ;
191
+ else
192
+ {
193
+ DoStack ( newSlide , oldSlide ) ;
194
+ oldSlide . Opacity = 0 ;
195
+ }
196
+ }
197
+ else if ( oldSlide != null || newSlide != null )
198
+ {
199
+ DoStack ( oldSlide ?? newSlide ) ;
200
+ if ( oldSlide != null )
201
+ {
202
+ oldSlide . Opacity = 0 ;
203
+ }
204
+ }
205
+
206
+ _nextTransitionOrigin = null ;
207
+ }
208
+
209
+ void IZIndexController . Stack ( params TransitionerSlide [ ] highestToLowest )
210
+ {
211
+ DoStack ( highestToLowest ) ;
212
+ }
213
+
214
+ private static void DoStack ( params TransitionerSlide [ ] highestToLowest )
215
+ {
216
+ if ( highestToLowest == null ) return ;
217
+
218
+ var pos = highestToLowest . Length ;
219
+ foreach ( var slide in highestToLowest . Where ( s => s != null ) )
220
+ {
221
+ Panel . SetZIndex ( slide , pos -- ) ;
222
+ }
223
+ }
224
+ }
225
+ }
0 commit comments