@@ -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