diff --git a/components/MarqueeText/samples/CustomStyleMarqueeTextSample.xaml b/components/MarqueeText/samples/CustomStyleMarqueeTextSample.xaml
new file mode 100644
index 000000000..5ae3e61ed
--- /dev/null
+++ b/components/MarqueeText/samples/CustomStyleMarqueeTextSample.xaml
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/MarqueeText/samples/CustomStyleMarqueeTextSample.xaml.cs b/components/MarqueeText/samples/CustomStyleMarqueeTextSample.xaml.cs
new file mode 100644
index 000000000..45008f2c9
--- /dev/null
+++ b/components/MarqueeText/samples/CustomStyleMarqueeTextSample.xaml.cs
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using CommunityToolkit.Labs.WinUI.MarqueeTextRns;
+
+namespace MarqueeTextExperiment.Samples;
+
+[ToolkitSample(id: nameof(CustomStyleMarqueeTextSample), "MarqueeText", description: "A control for scrolling text in a marquee fashion.")]
+[ToolkitSampleTextOption("MQText", LoremIpsum, Title = "Text")]
+//[ToolkitSampleMultiChoiceOption("MarqueeRepeat", "Repeat", "Forever", "1x", "2x")]
+public sealed partial class CustomStyleMarqueeTextSample : Page
+{
+ private const string LoremIpsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
+
+ public CustomStyleMarqueeTextSample()
+ {
+ this.InitializeComponent();
+ }
+
+ private MarqueeDirection ConvertStringToMarqueeDirection(string str) => str switch
+ {
+ "Left" => MarqueeDirection.Left,
+ "Up" => MarqueeDirection.Up,
+ "Right" => MarqueeDirection.Right,
+ "Down" => MarqueeDirection.Down,
+ _ => throw new System.NotImplementedException(),
+ };
+}
diff --git a/components/MarqueeText/samples/MarqueeText.Samples.csproj b/components/MarqueeText/samples/MarqueeText.Samples.csproj
index fc4e7acb7..71cf1d437 100644
--- a/components/MarqueeText/samples/MarqueeText.Samples.csproj
+++ b/components/MarqueeText/samples/MarqueeText.Samples.csproj
@@ -17,9 +17,17 @@
+
+ PreserveNewest
+
+
+
+ CustomStyleMarqueeTextSample.xaml
+
+
diff --git a/components/MarqueeText/samples/MarqueeText.md b/components/MarqueeText/samples/MarqueeText.md
index 786ee98f9..ea8480504 100644
--- a/components/MarqueeText/samples/MarqueeText.md
+++ b/components/MarqueeText/samples/MarqueeText.md
@@ -44,3 +44,9 @@ The repeat behavior determines how many times the marquee will loop before the a
The default direction is left, meaning the text will move leftwards, but this can be changed to right, up, or down. Direction changed between left and right or up and down are handled continously, meaning that the animation will resume from its current position if changed between these directions.
> [!Sample MarqueeTextSample]
+
+### Custom Transition Animations
+
+The transition animation can be customized using a style.
+
+> [!Sample CustomStyleMarqueeTextSample]
diff --git a/components/MarqueeText/samples/MarqueeTextSample.xaml b/components/MarqueeText/samples/MarqueeTextSample.xaml
index 292baeff4..339ac8087 100644
--- a/components/MarqueeText/samples/MarqueeTextSample.xaml
+++ b/components/MarqueeText/samples/MarqueeTextSample.xaml
@@ -1,4 +1,4 @@
-
+
-
+ Text="{x:Bind MQText, Mode=OneWay}" />
+
+
diff --git a/components/MarqueeText/samples/MarqueeTextSample.xaml.cs b/components/MarqueeText/samples/MarqueeTextSample.xaml.cs
index 8c3cc3ff7..810f0e162 100644
--- a/components/MarqueeText/samples/MarqueeTextSample.xaml.cs
+++ b/components/MarqueeText/samples/MarqueeTextSample.xaml.cs
@@ -5,17 +5,21 @@
using CommunityToolkit.Labs.WinUI.MarqueeTextRns;
namespace MarqueeTextExperiment.Samples;
+
[ToolkitSample(id: nameof(MarqueeTextSample), "MarqueeText", description: "A control for scrolling text in a marquee fashion.")]
+[ToolkitSampleTextOption("MQText", LoremIpsum, Title = "Text")]
[ToolkitSampleNumericOption("MQSpeed", initial: 96, min: 48, max: 196, step: 1, Title = "Speed")]
[ToolkitSampleMultiChoiceOption("MQDirection", "Left", "Right", "Up", "Down", Title = "Marquee Direction")]
//[ToolkitSampleMultiChoiceOption("MarqueeRepeat", "Repeat", "Forever", "1x", "2x")]
#if !HAS_UNO
-[ToolkitSampleMultiChoiceOption("MQBehavior", "Ticker", "Looping", "Bouncing", Title = "Marquee Behavior")]
+[ToolkitSampleMultiChoiceOption("MQBehavior", "Ticker", "Looping", "Bouncing", "Transition", Title = "Marquee Behavior")]
#else
-[ToolkitSampleMultiChoiceOption("MQBehavior", "Ticker", "Looping", Title = "Marquee Behavior")]
+[ToolkitSampleMultiChoiceOption("MQBehavior", "Ticker", "Looping", "Transition", Title = "Marquee Behavior")]
#endif
public sealed partial class MarqueeTextSample : Page
{
+ private const string LoremIpsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
+
public MarqueeTextSample()
{
this.InitializeComponent();
@@ -28,7 +32,8 @@ public MarqueeTextSample()
#if !HAS_UNO
"Bouncing" => MarqueeBehavior.Bouncing,
#endif
- _ => throw new System.NotImplementedException(),
+ "Transition" => MarqueeBehavior.Transition,
+ _ => throw new NotImplementedException(),
};
private MarqueeDirection ConvertStringToMarqueeDirection(string str) => str switch
@@ -39,4 +44,9 @@ public MarqueeTextSample()
"Down" => MarqueeDirection.Down,
_ => throw new System.NotImplementedException(),
};
+
+ private void StartMarquee_Click(object sender, RoutedEventArgs e)
+ {
+ Marquee?.StartMarquee();
+ }
}
diff --git a/components/MarqueeText/src/MarqueeBehavior.cs b/components/MarqueeText/src/MarqueeBehavior.cs
index 18942c448..d663190c8 100644
--- a/components/MarqueeText/src/MarqueeBehavior.cs
+++ b/components/MarqueeText/src/MarqueeBehavior.cs
@@ -29,4 +29,9 @@ public enum MarqueeBehavior
///
Bouncing,
#endif
+
+ ///
+ /// The text will transition when the text property changes.
+ ///
+ Transition,
}
diff --git a/components/MarqueeText/src/MarqueeDirection.cs b/components/MarqueeText/src/MarqueeDirection.cs
index 37117a939..d2ab52fdf 100644
--- a/components/MarqueeText/src/MarqueeDirection.cs
+++ b/components/MarqueeText/src/MarqueeDirection.cs
@@ -10,22 +10,22 @@ namespace CommunityToolkit.Labs.WinUI.MarqueeTextRns;
public enum MarqueeDirection
{
///
- /// The text will flow from left to right.
+ /// The text will move from left to right.
///
Left,
///
- /// The text will flow from right to left.
+ /// The text will move from right to left.
///
Right,
///
- /// The text will flow from bottom to top.
+ /// The text will move from bottom to top.
///
Up,
///
- /// The text will flow from top to bottom.
+ /// The text will move from top to bottom.
///
Down,
}
diff --git a/components/MarqueeText/src/MarqueeText.Events.cs b/components/MarqueeText/src/MarqueeText.Events.cs
index 828b325ed..624695b92 100644
--- a/components/MarqueeText/src/MarqueeText.Events.cs
+++ b/components/MarqueeText/src/MarqueeText.Events.cs
@@ -47,18 +47,25 @@ private void Container_SizeChanged(object sender, SizeChangedEventArgs e)
}
// Clip the marquee within its bounds
- _marqueeContainer.Clip = new RectangleGeometry
- {
- Rect = new Rect(0, 0, e.NewSize.Width, e.NewSize.Height)
- };
+ UpdateClipping();
- // The marquee should run when the size changes in case the text gets cutoff
- StartMarquee();
+ // Update the animation when the size changes
+ // Unless in transition mode where the container size doesn't affect the animation.
+ if (!IsTransition)
+ {
+ UpdateAnimation(true);
+ }
}
private void StoryBoard_Completed(object? sender, object e)
{
StopMarquee(true);
MarqueeCompleted?.Invoke(this, EventArgs.Empty);
+
+ // Update the secondary text to match the new text
+ if (IsTransition)
+ {
+ SecondaryText = Text;
+ }
}
}
diff --git a/components/MarqueeText/src/MarqueeText.Properties.cs b/components/MarqueeText/src/MarqueeText.Properties.cs
index c7f207255..0bab8c7c0 100644
--- a/components/MarqueeText/src/MarqueeText.Properties.cs
+++ b/components/MarqueeText/src/MarqueeText.Properties.cs
@@ -12,7 +12,10 @@ namespace CommunityToolkit.Labs.WinUI.MarqueeTextRns;
public partial class MarqueeText
{
private static readonly DependencyProperty TextProperty =
- DependencyProperty.Register(nameof(Text), typeof(string), typeof(MarqueeText), new PropertyMetadata(null, PropertyChanged));
+ DependencyProperty.Register(nameof(Text), typeof(string), typeof(MarqueeText), new PropertyMetadata(null, TextPropertyChanged));
+
+ private static readonly DependencyProperty SecondaryTextProperty =
+ DependencyProperty.Register(nameof(SecondaryText), typeof(string), typeof(MarqueeText), new PropertyMetadata(null));
private static readonly DependencyProperty SpeedProperty =
DependencyProperty.Register(nameof(Speed), typeof(double), typeof(MarqueeText), new PropertyMetadata(32d, PropertyChanged));
@@ -40,9 +43,21 @@ public string Text
set => SetValue(TextProperty, value);
}
+ ///
+ /// Gets a secondary text field used for binding the secondary text block.
+ ///
+ public string SecondaryText
+ {
+ get => (string)GetValue(SecondaryTextProperty);
+ private set => SetValue(SecondaryTextProperty, value);
+ }
+
///
/// Gets or sets the speed the text moves in the Marquee.
///
+ ///
+ /// Ignored if the behavior is
+ ///
public double Speed
{
get => (double)GetValue(SpeedProperty);
@@ -52,6 +67,9 @@ public double Speed
///
/// Gets or sets a value indicating whether or not the marquee scroll repeats.
///
+ ///
+ /// Ignored if the behavior is
+ ///
public RepeatBehavior RepeatBehavior
{
get => (RepeatBehavior)GetValue(RepeatBehaviorProperty);
@@ -61,6 +79,9 @@ public RepeatBehavior RepeatBehavior
///
/// Gets or sets the marquee behavior.
///
+ ///
+ /// When the text won't scroll if the text can already fit in the screen.
+ ///
public MarqueeBehavior Behavior
{
get => (MarqueeBehavior)GetValue(BehaviorProperty);
@@ -77,12 +98,11 @@ public MarqueeBehavior Behavior
private bool IsBouncing => false;
#endif
+ private bool IsTransition => Behavior == MarqueeBehavior.Transition;
+
///
- /// Gets or sets a value indicating whether or not the marquee text wraps.
+ /// Gets or sets the direction the Marquee should scroll
///
- ///
- /// Wrapping text won't scroll if the text can already fit in the screen.
- ///
public MarqueeDirection Direction
{
get => (MarqueeDirection)GetValue(DirectionProperty);
@@ -91,7 +111,7 @@ public MarqueeDirection Direction
private bool IsDirectionHorizontal => Direction is MarqueeDirection.Left or MarqueeDirection.Right;
- private bool IsDirectionInverse => Direction is MarqueeDirection.Up or MarqueeDirection.Right;
+ private bool IsDirectionInverse => Direction is MarqueeDirection.Down or MarqueeDirection.Right;
// Waiting on https://github.com/unoplatform/uno/issues/12929
#if !HAS_UNO
@@ -114,7 +134,8 @@ private static void BehaviorPropertyChanged(DependencyObject d, DependencyProper
bool active = control._isActive;
var newBehavior = (MarqueeBehavior)e.NewValue;
-
+
+ control.UpdateClipping();
VisualStateManager.GoToState(control, GetVisualStateName(newBehavior), true);
control.StopMarquee(false);
@@ -137,19 +158,43 @@ private static void DirectionPropertyChanged(DependencyObject d, DependencyPrope
bool oldAxisX = oldDirection is MarqueeDirection.Left or MarqueeDirection.Right;
bool newAxisX = newDirection is MarqueeDirection.Left or MarqueeDirection.Right;
- VisualStateManager.GoToState(control, GetVisualStateName(newDirection), true);
-
- if (oldAxisX != newAxisX)
+ if (control.IsTransition || oldAxisX != newAxisX)
{
control.StopMarquee(false);
}
+ VisualStateManager.GoToState(control, GetVisualStateName(newDirection), true);
+
if (active)
{
control.StartMarquee();
}
}
+ private static void TextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is not MarqueeText control)
+ {
+ return;
+ }
+
+ // If the mode is not transition, update the secondary text to match and handle with standard property changed.
+ if (!control.IsTransition)
+ {
+ control.SecondaryText = (string)e.NewValue;
+ PropertyChanged(d, e);
+ return;
+ }
+
+ if (!control._isActive)
+ {
+ // If the mode is transition, start the marquee.
+ // We can skip this if the animation is already
+ // playing because that's smoother than starting a new animation.
+ control.StartMarquee();
+ }
+ }
+
private static void PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is not MarqueeText control)
diff --git a/components/MarqueeText/src/MarqueeText.cs b/components/MarqueeText/src/MarqueeText.cs
index d84ae71fb..e8b9e9d47 100644
--- a/components/MarqueeText/src/MarqueeText.cs
+++ b/components/MarqueeText/src/MarqueeText.cs
@@ -12,6 +12,7 @@ namespace CommunityToolkit.Labs.WinUI.MarqueeTextRns;
[TemplatePart(Name = Segment2PartName, Type = typeof(FrameworkTemplate))]
[TemplatePart(Name = Segment2PartName, Type = typeof(FrameworkTemplate))]
[TemplatePart(Name = MarqueeTransformPartName, Type = typeof(TranslateTransform))]
+[TemplatePart(Name = TransitionAnaimationPartName, Type = typeof(Storyboard))]
[TemplateVisualState(GroupName = DirectionVisualStateGroupName, Name = LeftwardsVisualStateName)]
[TemplateVisualState(GroupName = DirectionVisualStateGroupName, Name = RightwardsVisualStateName)]
[TemplateVisualState(GroupName = DirectionVisualStateGroupName, Name = UpwardsVisualStateName)]
@@ -19,6 +20,7 @@ namespace CommunityToolkit.Labs.WinUI.MarqueeTextRns;
[TemplateVisualState(GroupName = BehaviorVisualStateGroupName, Name = TickerVisualStateName)]
[TemplateVisualState(GroupName = BehaviorVisualStateGroupName, Name = LoopingVisualStateName)]
[TemplateVisualState(GroupName = BehaviorVisualStateGroupName, Name = BouncingVisualStateName)]
+[TemplateVisualState(GroupName = BehaviorVisualStateGroupName, Name = TransitionVisualStateName)]
[ContentProperty(Name = nameof(Text))]
#if HAS_UNO
@@ -31,6 +33,7 @@ public partial class MarqueeText : Control
private const string Segment1PartName = "Segment1";
private const string Segment2PartName = "Segment2";
private const string MarqueeTransformPartName = "MarqueeTransform";
+ private const string TransitionAnaimationPartName = "TransitionAnimation";
private const string MarqueeActiveState = "MarqueeActive";
private const string MarqueeStoppedState = "MarqueeStopped";
@@ -45,11 +48,13 @@ public partial class MarqueeText : Control
private const string TickerVisualStateName = "Ticker";
private const string LoopingVisualStateName = "Looping";
private const string BouncingVisualStateName = "Bouncing";
+ private const string TransitionVisualStateName = "Transition";
private Panel? _marqueeContainer;
private FrameworkElement? _segment1;
private FrameworkElement? _segment2;
- private TranslateTransform? _marqueeTransform;
+ private CompositeTransform? _marqueeTransform;
+ private Storyboard? _transitionStoryboard;
private Storyboard? _marqueeStoryboard;
private bool _isActive;
@@ -71,7 +76,8 @@ protected override void OnApplyTemplate()
_marqueeContainer = (Panel)GetTemplateChild(MarqueeContainerPartName);
_segment1 = (FrameworkElement)GetTemplateChild(Segment1PartName);
_segment2 = (FrameworkElement)GetTemplateChild(Segment2PartName);
- _marqueeTransform = (TranslateTransform)GetTemplateChild(MarqueeTransformPartName);
+ _marqueeTransform = (CompositeTransform)GetTemplateChild(MarqueeTransformPartName);
+ _transitionStoryboard = (Storyboard)GetTemplateChild(TransitionAnaimationPartName);
_marqueeContainer.SizeChanged += Container_SizeChanged;
@@ -82,6 +88,7 @@ protected override void OnApplyTemplate()
VisualStateManager.GoToState(this, GetVisualStateName(Direction), false);
VisualStateManager.GoToState(this, GetVisualStateName(Behavior), false);
+ StopMarquee();
}
private static string GetVisualStateName(MarqueeDirection direction)
@@ -162,7 +169,8 @@ private bool UpdateAnimation(bool resume = true)
if (_marqueeContainer is null ||
_marqueeTransform is null ||
_segment1 is null ||
- _segment2 is null)
+ _segment2 is null ||
+ _transitionStoryboard is null)
{
return false;
}
@@ -171,6 +179,7 @@ _segment1 is null ||
// Update the animation to the stopped position.
if (!_isActive)
{
+ _marqueeStoryboard?.Stop();
VisualStateManager.GoToState(this, MarqueeStoppedState, false);
return false;
@@ -189,8 +198,8 @@ _segment1 is null ||
// are defined by width and X coordinates.
containerSize = _marqueeContainer.ActualWidth;
segmentSize = _segment1.ActualWidth;
- value = _marqueeTransform.X;
- targetProperty = "(TranslateTransform.X)";
+ value = _marqueeTransform.TranslateX;
+ targetProperty = "(CompositeTransform.TranslateX)";
}
else
{
@@ -198,8 +207,8 @@ _segment1 is null ||
// are defined by height and Y coordinates.
containerSize = _marqueeContainer.ActualHeight;
segmentSize = _segment1.ActualHeight;
- value = _marqueeTransform.Y;
- targetProperty = "(TranslateTransform.Y)";
+ value = _marqueeTransform.TranslateY;
+ targetProperty = "(CompositeTransform.TranslateY)";
}
if (IsLooping && segmentSize < containerSize)
@@ -211,7 +220,6 @@ _segment1 is null ||
// calling update animation. If _isActive were passed, it would allow for
// MarqueeStopped to be invoked when the marquee was already stopped.
StopMarquee(resume);
- _segment2.Visibility = Visibility.Collapsed;
return false;
}
@@ -220,9 +228,24 @@ _segment1 is null ||
// Otherwise it's 0
double start = IsTicker ? containerSize : 0;
- // The end is when the end of the text reaches the border if in bouncing mode
- // Otherwise it is when the first set of text is 100% out of view
- double end = IsBouncing ? containerSize - segmentSize : -segmentSize;
+ double end = Behavior switch
+ {
+ // (this value just needs to be non-Zero, the real number is handled in the Style)
+ MarqueeBehavior.Transition => 20,
+#if !HAS_UNO
+ // When the end of the text reaches the border if in bouncing mode
+ MarqueeBehavior.Bouncing => containerSize - segmentSize,
+#endif
+ // When the first set of text is 100% out of view
+ MarqueeBehavior.Ticker or MarqueeBehavior.Looping or _ => -segmentSize,
+ };
+
+ // Swap the directions if inverse direction animation
+ if (IsDirectionInverse)
+ {
+ // Swap the start and end to inverse direction for right or upwards
+ (start, end) = (end, start);
+ }
// The distance is used for calculating the duration and the previous
// animation progress if resuming
@@ -234,30 +257,26 @@ _segment1 is null ||
return false;
}
- // Swap the start and end to inverse direction for right or upwards
- if (IsDirectionInverse)
- {
- (start, end) = (end, start);
- }
-
- // The second segment of text should be hidden if the marquee is not in looping mode
- _segment2.Visibility = IsLooping ? Visibility.Visible : Visibility.Collapsed;
-
// Calculate the animation duration by dividing the distance by the speed
TimeSpan duration = TimeSpan.FromSeconds(distance / Speed);
-
- // Unbind events from the old storyboard
+
+ // Unbind events from the old storyboard and stop it before disposal.
if (_marqueeStoryboard is not null)
{
_marqueeStoryboard.Completed -= StoryBoard_Completed;
+ _marqueeStoryboard?.Stop();
}
// Create new storyboard and animation
- _marqueeStoryboard = CreateMarqueeStoryboardAnimation(start, end, duration, targetProperty);
+ _marqueeStoryboard = Behavior switch
+ {
+ MarqueeBehavior.Transition => _transitionStoryboard,
+ _ => CreateMarqueeStoryboardAnimation(start, end, duration, targetProperty),
+ };
// Bind the storyboard completed event
_marqueeStoryboard.Completed += StoryBoard_Completed;
-
+
// Set the visual state to active and begin the animation
VisualStateManager.GoToState(this, MarqueeActiveState, true);
_marqueeStoryboard.Begin();
@@ -272,8 +291,11 @@ _segment1 is null ||
return true;
}
+ ///
+ /// This is method is used for all modes except transition.
+ ///
private Storyboard CreateMarqueeStoryboardAnimation(double start, double end, TimeSpan duration, string targetProperty)
- {
+ {
// Initialize the new storyboard
var marqueeStoryboard = new Storyboard
{
@@ -285,7 +307,7 @@ private Storyboard CreateMarqueeStoryboardAnimation(double start, double end, Ti
};
// Create a new double animation, moving from [start] to [end] positions in [duration] time.
- var animation = new DoubleAnimationUsingKeyFrames
+ var posAnim = new DoubleAnimationUsingKeyFrames
{
Duration = duration,
RepeatBehavior = RepeatBehavior,
@@ -293,32 +315,51 @@ private Storyboard CreateMarqueeStoryboardAnimation(double start, double end, Ti
AutoReverse = IsBouncing,
#endif
};
+
+ // Set the animation target and target property
+ Storyboard.SetTarget(posAnim, _marqueeTransform);
+ Storyboard.SetTargetProperty(posAnim, targetProperty);
// Create the key frames
- var frame1 = new DiscreteDoubleKeyFrame
+ var posFrame0 = new LinearDoubleKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero),
Value = start,
};
- var frame2 = new EasingDoubleKeyFrame
+ var posFrame1 = new LinearDoubleKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(duration),
Value = end,
};
// Add the key frames to the animation
- animation.KeyFrames.Add(frame1);
- animation.KeyFrames.Add(frame2);
+ posAnim.KeyFrames.Add(posFrame0);
+ posAnim.KeyFrames.Add(posFrame1);
// Add the double animation to the storyboard
- marqueeStoryboard.Children.Add(animation);
-
- // Set the storyboard target and target property
- Storyboard.SetTarget(animation, _marqueeTransform);
- Storyboard.SetTargetProperty(animation, targetProperty);
+ marqueeStoryboard.Children.Add(posAnim);
return marqueeStoryboard;
}
+
+ private void UpdateClipping()
+ {
+ if (_marqueeContainer is null)
+ {
+ return;
+ }
+
+ _marqueeContainer.Clip = new RectangleGeometry
+ {
+ Rect = new Rect(0, 0, ActualWidth, ActualHeight)
+ };
+
+ if (IsTransition)
+ {
+ // Don't clip in transition mode
+ _marqueeContainer.Clip = null;
+ }
+ }
}
#if HAS_UNO
diff --git a/components/MarqueeText/src/MarqueeText.xaml b/components/MarqueeText/src/MarqueeText.xaml
index 3efaf4075..adb49863f 100644
--- a/components/MarqueeText/src/MarqueeText.xaml
+++ b/components/MarqueeText/src/MarqueeText.xaml
@@ -1,4 +1,4 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
@@ -31,21 +81,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -53,16 +115,25 @@
+
+
+
+
+
+
+
+
+
@@ -72,7 +143,7 @@
-
+
+ Text="{TemplateBinding SecondaryText}"
+ Visibility="Collapsed" />
diff --git a/tooling b/tooling
index 819a01607..ce05388f0 160000
--- a/tooling
+++ b/tooling
@@ -1 +1 @@
-Subproject commit 819a01607310fad9bf52097423977ace4b5c372a
+Subproject commit ce05388f0ad2f241612a28a0e03cb58c80515e65