Skip to content

Commit cc67ddd

Browse files
committed
Adjusted event bindings flow in Marquee control
1 parent 6052375 commit cc67ddd

File tree

2 files changed

+30
-20
lines changed

2 files changed

+30
-20
lines changed

components/Marquee/src/Marquee.Events.cs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@ public partial class Marquee
1212
/// <summary>
1313
/// Event raised when the Marquee begins scrolling.
1414
/// </summary>
15-
/// <remarks>
16-
/// Could be started. Could be resumed.
17-
/// </remarks>
1815
public event EventHandler? MarqueeStarted;
1916

2017
/// <summary>
@@ -41,14 +38,19 @@ private void Marquee_Loaded(object sender, RoutedEventArgs e)
4138
{
4239
// While loaded, detach the loaded event and attach the unloaded event
4340
this.Loaded -= this.Marquee_Loaded;
44-
this.Unloaded += Marquee_Unloaded;
41+
this.Unloaded += this.Marquee_Unloaded;
4542

4643
// Attach other events
4744
if (_marqueeContainer is not null)
4845
{
4946
_marqueeContainer.SizeChanged += Container_SizeChanged;
5047
}
5148

49+
if (_segment1 is not null)
50+
{
51+
_segment1.SizeChanged += Segment_SizeChanged;
52+
}
53+
5254
if (_marqueeStoryboard is not null)
5355
{
5456
_marqueeStoryboard.Completed += StoryBoard_Completed;
@@ -66,6 +68,11 @@ private void Marquee_Unloaded(object sender, RoutedEventArgs e)
6668
_marqueeContainer.SizeChanged -= Container_SizeChanged;
6769
}
6870

71+
if (_segment1 is not null)
72+
{
73+
_segment1.SizeChanged -= Segment_SizeChanged;
74+
}
75+
6976
if (_marqueeStoryboard is not null)
7077
{
7178
_marqueeStoryboard.Completed -= StoryBoard_Completed;
@@ -75,9 +82,7 @@ private void Marquee_Unloaded(object sender, RoutedEventArgs e)
7582
private void Container_SizeChanged(object sender, SizeChangedEventArgs e)
7683
{
7784
if (_marqueeContainer is null)
78-
{
7985
return;
80-
}
8186

8287
// Clip the marquee within its bounds
8388
_marqueeContainer.Clip = new RectangleGeometry
@@ -99,9 +104,7 @@ private void Container_SizeChanged(object sender, SizeChangedEventArgs e)
99104
private void Segment_SizeChanged(object sender, SizeChangedEventArgs e)
100105
{
101106
if (_segment1 is null)
102-
{
103107
return;
104-
}
105108

106109
// If the segment size changes, we need to update the storyboard,
107110
// and seek to the correct position to maintain a smooth animation.

components/Marquee/src/Marquee.cs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ public Marquee()
6161
DefaultStyleKey = typeof(Marquee);
6262
}
6363

64+
/// <summary>
65+
/// Unsubscribes from the loaded event when the control is being disposed.
66+
/// </summary>
67+
~Marquee()
68+
{
69+
Loaded -= this.Marquee_Loaded;
70+
}
71+
6472
/// <inheritdoc/>
6573
protected override void OnApplyTemplate()
6674
{
@@ -72,12 +80,10 @@ protected override void OnApplyTemplate()
7280
_segment2 = (ContentPresenter)GetTemplateChild(Segment2PartName);
7381
_marqueeTransform = (TranslateTransform)GetTemplateChild(MarqueeTransformPartName);
7482

75-
_marqueeContainer.SizeChanged += Container_SizeChanged;
76-
_segment1.SizeChanged += Segment_SizeChanged;
77-
7883
// Swapping tabs in TabView caused errors where the control would unload and never reattach events.
79-
// Hotfix: Track the loaded event. This should be fine because the GC will handle detaching the Loaded
80-
// event on disposal. However, more research is required
84+
// Fix: Track the loaded event. This should be fine because the GC will handle detaching the Loaded
85+
// event on disposal. However, more research is required.
86+
// As a result, all other events should be attached in the Loaded event handler.
8187
Loaded += this.Marquee_Loaded;
8288

8389
VisualStateManager.GoToState(this, GetVisualStateName(Direction), false);
@@ -192,7 +198,7 @@ private void PlayMarquee(bool fromStart = false)
192198
}
193199

194200
// Do nothing if storyboard is null or already playing and not from start.
195-
if (_marqueeStoryboard is null || _isActive && !fromStart)
201+
if (_marqueeStoryboard is null || (_isActive && !fromStart))
196202
return;
197203

198204
bool wasActive = _isActive;
@@ -269,6 +275,12 @@ private bool UpdateAnimation(out TimeSpan seekPoint)
269275
if (!HasTemplateParts())
270276
return false;
271277

278+
// Unbind events from the old storyboard
279+
if (_marqueeStoryboard is not null)
280+
{
281+
_marqueeStoryboard.Completed -= StoryBoard_Completed;
282+
}
283+
272284
// Get the size of the container and segment, based on the orientation.
273285
// Also track the property to adjust, also based on the orientation.
274286
double containerSize;
@@ -326,6 +338,7 @@ private bool UpdateAnimation(out TimeSpan seekPoint)
326338
// If the distance is zero, don't play an animation
327339
if (distance is 0)
328340
{
341+
_marqueeStoryboard = null;
329342
return false;
330343
}
331344

@@ -341,12 +354,6 @@ private bool UpdateAnimation(out TimeSpan seekPoint)
341354
// Calculate the animation duration by dividing the distance by the speed
342355
TimeSpan duration = TimeSpan.FromSeconds(distance / Speed);
343356

344-
// Unbind events from the old storyboard
345-
if (_marqueeStoryboard is not null)
346-
{
347-
_marqueeStoryboard.Completed -= StoryBoard_Completed;
348-
}
349-
350357
// Create new storyboard and animation
351358
_marqueeStoryboard = CreateMarqueeStoryboardAnimation(start, end, duration, targetProperty);
352359

0 commit comments

Comments
 (0)