1+ // ******************************************************************
2+ // Copyright (c) Microsoft. All rights reserved.
3+ // This code is licensed under the MIT License (MIT).
4+ // THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
5+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
7+ // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
8+ // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
9+ // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
10+ // THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
11+ // ******************************************************************
12+
13+ using Microsoft . Xaml . Interactivity ;
14+ using Windows . UI . Xaml ;
15+
16+ namespace Microsoft . Toolkit . Uwp . UI . Animations . Behaviors
17+ {
18+ /// <summary>
19+ /// Base class for behaviors that solves 2 problems:
20+ /// 1. Prevent duplicate initialization that can happen (prevent multiple OnAttached calls);
21+ /// 2. Whenever <see cref="Initialize"/> initially fails, this method will subscribe to <see cref="FrameworkElement.SizeChanged"/> to allow lazy initialization.
22+ /// </summary>
23+ /// <typeparam name="T">The type of the associated object.</typeparam>
24+ /// <seealso cref="Microsoft.Xaml.Interactivity.Behavior{T}" />
25+ /// <remarks>
26+ /// For more info, see https://github.com/Microsoft/UWPCommunityToolkit/issues/1008.
27+ /// </remarks>
28+ public abstract class BehaviorBase < T > : Behavior < T >
29+ where T : UIElement
30+ {
31+ private bool _isAttaching ;
32+ private bool _isAttached ;
33+
34+ /// <summary>
35+ /// Gets a value indicating whether this behavior is attached.
36+ /// </summary>
37+ /// <value>
38+ /// <c>true</c> if this behavior is attached; otherwise, <c>false</c>.
39+ /// </value>
40+ protected bool IsAttached
41+ {
42+ get { return _isAttached ; }
43+ }
44+
45+ /// <summary>
46+ /// Called after the behavior is attached to the <see cref="P:Microsoft.Xaml.Interactivity.Behavior.AssociatedObject" />.
47+ /// </summary>
48+ /// <remarks>
49+ /// Override this to hook up functionality to the <see cref="P:Microsoft.Xaml.Interactivity.Behavior.AssociatedObject" />
50+ /// </remarks>
51+ protected override void OnAttached ( )
52+ {
53+ base . OnAttached ( ) ;
54+
55+ HandleAttach ( ) ;
56+
57+ var frameworkElement = AssociatedObject as FrameworkElement ;
58+ if ( frameworkElement != null )
59+ {
60+ frameworkElement . Loaded += OnAssociatedObjectLoaded ;
61+ frameworkElement . Unloaded += OnAssociatedObjectUnloaded ;
62+ frameworkElement . SizeChanged += OnAssociatedObjectSizeChanged ;
63+ }
64+ }
65+
66+ /// <summary>
67+ /// Called when the behavior is being detached from its <see cref="P:Microsoft.Xaml.Interactivity.Behavior.AssociatedObject" />.
68+ /// </summary>
69+ /// <remarks>
70+ /// Override this to unhook functionality from the <see cref="P:Microsoft.Xaml.Interactivity.Behavior.AssociatedObject" />
71+ /// </remarks>
72+ protected override void OnDetaching ( )
73+ {
74+ base . OnDetaching ( ) ;
75+
76+ var frameworkElement = AssociatedObject as FrameworkElement ;
77+ if ( frameworkElement != null )
78+ {
79+ frameworkElement . Loaded -= OnAssociatedObjectLoaded ;
80+ frameworkElement . Unloaded -= OnAssociatedObjectUnloaded ;
81+ frameworkElement . SizeChanged -= OnAssociatedObjectSizeChanged ;
82+ }
83+
84+ HandleDetach ( ) ;
85+ }
86+
87+ /// <summary>
88+ /// Called when the associated object has been loaded.
89+ /// </summary>
90+ protected virtual void OnAssociatedObjectLoaded ( )
91+ {
92+ }
93+
94+ /// <summary>
95+ /// Called when the associated object has been unloaded.
96+ /// </summary>
97+ protected virtual void OnAssociatedObjectUnloaded ( )
98+ {
99+ }
100+
101+ /// <summary>
102+ /// Initializes the behavior to the associated object.
103+ /// </summary>
104+ /// <returns><c>true</c> if the initialization succeeded; otherwise <c>false</c>.</returns>
105+ protected virtual bool Initialize ( )
106+ {
107+ return true ;
108+ }
109+
110+ /// <summary>
111+ /// Uninitializes the behavior from the associated object.
112+ /// </summary>
113+ /// <returns><c>true</c> if uninitialization succeeded; otherwise <c>false</c>.</returns>
114+ protected virtual bool Uninitialize ( )
115+ {
116+ return true ;
117+ }
118+
119+ private void OnAssociatedObjectLoaded ( object sender , RoutedEventArgs e )
120+ {
121+ if ( ! _isAttached )
122+ {
123+ HandleAttach ( ) ;
124+ }
125+
126+ OnAssociatedObjectLoaded ( ) ;
127+ }
128+
129+ private void OnAssociatedObjectUnloaded ( object sender , RoutedEventArgs e )
130+ {
131+ OnAssociatedObjectUnloaded ( ) ;
132+
133+ // Note: don't detach here, we'll let the behavior implementation take care of that
134+ }
135+
136+ private void OnAssociatedObjectSizeChanged ( object sender , SizeChangedEventArgs e )
137+ {
138+ if ( ! _isAttached )
139+ {
140+ HandleAttach ( ) ;
141+ }
142+ }
143+
144+ private void HandleAttach ( )
145+ {
146+ if ( _isAttaching || _isAttached )
147+ {
148+ return ;
149+ }
150+
151+ _isAttaching = true ;
152+
153+ var attached = Initialize ( ) ;
154+ if ( attached )
155+ {
156+ _isAttached = true ;
157+ }
158+
159+ _isAttaching = false ;
160+ }
161+
162+ private void HandleDetach ( )
163+ {
164+ if ( ! _isAttached )
165+ {
166+ return ;
167+ }
168+
169+ var detached = Uninitialize ( ) ;
170+ if ( detached )
171+ {
172+ _isAttached = false ;
173+ }
174+ }
175+ }
176+ }
0 commit comments