Skip to content

Commit 238d287

Browse files
committed
2 parents 8e073da + e51557b commit 238d287

File tree

13 files changed

+334
-219
lines changed

13 files changed

+334
-219
lines changed
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
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+
}

Microsoft.Toolkit.Uwp.UI.Animations/Behaviors/Blur.cs

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Animations.Behaviors
2828
/// <cref>Microsoft.Xaml.Interactivity.Behavior{Windows.UI.Xaml.UIElement}</cref>
2929
/// </seealso>
3030
/// <seealso cref="AnimationExtensions.IsBlurSupported"/>
31-
public class Blur : CompositionBehaviorBase
31+
public class Blur : CompositionBehaviorBase<FrameworkElement>
3232
{
33-
/// <summary>
34-
/// The _framework element
35-
/// </summary>
36-
private FrameworkElement _frameworkElement;
37-
38-
/// <summary>
39-
/// Called after the behavior is attached to the <see cref="P:Microsoft.Xaml.Interactivity.Behavior.AssociatedObject" />.
40-
/// </summary>
41-
/// <remarks>
42-
/// Override this to hook up functionality to the <see cref="P:Microsoft.Xaml.Interactivity.Behavior.AssociatedObject" />
43-
/// </remarks>
44-
protected override void OnAttached()
45-
{
46-
base.OnAttached();
47-
_frameworkElement = AssociatedObject as FrameworkElement;
48-
}
49-
5033
/// <summary>
5134
/// The Blur value of the associated object
5235
/// </summary>
@@ -71,7 +54,7 @@ public override void StartAnimation()
7154
{
7255
if (AnimationExtensions.BlurEffect.IsSupported)
7356
{
74-
_frameworkElement?.Blur(duration: Duration, delay: Delay, value: (float)Value)?.StartAsync();
57+
AssociatedObject?.Blur(duration: Duration, delay: Delay, value: (float)Value)?.Start();
7558
}
7659
}
7760
}

Microsoft.Toolkit.Uwp.UI.Animations/Behaviors/CompositionBehaviorBase.cs

Lines changed: 16 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10,52 +10,25 @@
1010
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
1111
// ******************************************************************
1212

13-
using Microsoft.Xaml.Interactivity;
1413
using Windows.UI.Xaml;
1514

1615
namespace Microsoft.Toolkit.Uwp.UI.Animations.Behaviors
1716
{
1817
/// <summary>
1918
/// A base class for all behaviors using composition.It contains some of the common propeties to set on a visual.
2019
/// </summary>
21-
public abstract class CompositionBehaviorBase : Behavior<UIElement>
20+
/// <typeparam name="T">The type of the associated object.</typeparam>
21+
/// <seealso cref="Microsoft.Toolkit.Uwp.UI.Animations.Behaviors.BehaviorBase{T}" />
22+
public abstract class CompositionBehaviorBase<T> : BehaviorBase<T>
23+
where T : UIElement
2224
{
2325
/// <summary>
24-
/// Called after the behavior is attached to the <see cref="P:Microsoft.Xaml.Interactivity.Behavior.AssociatedObject" />.
26+
/// Called when the associated object has been loaded.
2527
/// </summary>
26-
/// <remarks>
27-
/// Override this to hook up functionality to the <see cref="P:Microsoft.Xaml.Interactivity.Behavior.AssociatedObject" />
28-
/// </remarks>
29-
protected override void OnAttached()
28+
protected override void OnAssociatedObjectLoaded()
3029
{
31-
base.OnAttached();
30+
base.OnAssociatedObjectLoaded();
3231

33-
var frameworkElement = AssociatedObject as FrameworkElement;
34-
if (frameworkElement != null)
35-
{
36-
frameworkElement.Loaded += OnFrameworkElementLoaded;
37-
}
38-
}
39-
40-
/// <summary>
41-
/// Called while the behavior is detaching from the <see cref="P:Microsoft.Xaml.Interactivity.Behavior.AssociatedObject" />.
42-
/// </summary>
43-
/// <remarks>
44-
/// Override this to finalize and free everything associated to the <see cref="P:Microsoft.Xaml.Interactivity.Behavior.AssociatedObject" />
45-
/// </remarks>
46-
protected override void OnDetaching()
47-
{
48-
base.OnDetaching();
49-
50-
var frameworkElement = AssociatedObject as FrameworkElement;
51-
if (frameworkElement != null)
52-
{
53-
frameworkElement.Loaded -= OnFrameworkElementLoaded;
54-
}
55-
}
56-
57-
private void OnFrameworkElementLoaded(object sender, RoutedEventArgs e)
58-
{
5932
if (AutomaticallyStart)
6033
{
6134
StartAnimation();
@@ -65,17 +38,17 @@ private void OnFrameworkElementLoaded(object sender, RoutedEventArgs e)
6538
/// <summary>
6639
/// The duration of the animation.
6740
/// </summary>
68-
public static readonly DependencyProperty DurationProperty = DependencyProperty.Register(nameof(Duration), typeof(double), typeof(CompositionBehaviorBase), new PropertyMetadata(1d, PropertyChangedCallback));
41+
public static readonly DependencyProperty DurationProperty = DependencyProperty.Register(nameof(Duration), typeof(double), typeof(CompositionBehaviorBase<T>), new PropertyMetadata(1d, PropertyChangedCallback));
6942

7043
/// <summary>
7144
/// The delay of the animation.
7245
/// </summary>
73-
public static readonly DependencyProperty DelayProperty = DependencyProperty.Register(nameof(Delay), typeof(double), typeof(CompositionBehaviorBase), new PropertyMetadata(0d, PropertyChangedCallback));
46+
public static readonly DependencyProperty DelayProperty = DependencyProperty.Register(nameof(Delay), typeof(double), typeof(CompositionBehaviorBase<T>), new PropertyMetadata(0d, PropertyChangedCallback));
7447

7548
/// <summary>
7649
/// The property sets if the animation should automatically start.
7750
/// </summary>
78-
public static readonly DependencyProperty AutomaticallyStartProperty = DependencyProperty.Register(nameof(AutomaticallyStart), typeof(bool), typeof(CompositionBehaviorBase), new PropertyMetadata(true, PropertyChangedCallback));
51+
public static readonly DependencyProperty AutomaticallyStartProperty = DependencyProperty.Register(nameof(AutomaticallyStart), typeof(bool), typeof(CompositionBehaviorBase<T>), new PropertyMetadata(true, PropertyChangedCallback));
7952

8053
/// <summary>
8154
/// Gets or sets a value indicating whether [automatically start] on the animation is set.
@@ -125,9 +98,13 @@ public double Duration
12598
/// <param name="dependencyPropertyChangedEventArgs">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
12699
protected static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
127100
{
128-
var behavior = dependencyObject as CompositionBehaviorBase;
101+
var behavior = dependencyObject as CompositionBehaviorBase<T>;
102+
if (behavior == null)
103+
{
104+
return;
105+
}
129106

130-
if (behavior?.AutomaticallyStart ?? false)
107+
if (behavior.AutomaticallyStart)
131108
{
132109
behavior.StartAnimation();
133110
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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 Windows.UI.Xaml;
14+
15+
namespace Microsoft.Toolkit.Uwp.UI.Animations.Behaviors
16+
{
17+
/// <summary>
18+
/// Non-generic convenience implementation to provide backwards compatibility.
19+
/// </summary>
20+
/// <seealso cref="Microsoft.Toolkit.Uwp.UI.Animations.Behaviors.CompositionBehaviorBase{T}" />
21+
public abstract class CompositionBehaviorBase : CompositionBehaviorBase<UIElement>
22+
{
23+
}
24+
}

Microsoft.Toolkit.Uwp.UI.Animations/Behaviors/Fade.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Animations.Behaviors
2020
/// <seealso>
2121
/// <cref>Microsoft.Xaml.Interactivity.Behavior{Windows.UI.Xaml.UIElement}</cref>
2222
/// </seealso>
23-
public class Fade : CompositionBehaviorBase
23+
public class Fade : CompositionBehaviorBase<UIElement>
2424
{
2525
/// <summary>
2626
/// The Opacity value of the associated object

0 commit comments

Comments
 (0)