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