Skip to content

Commit e648750

Browse files
authored
Merge pull request #735 from Avid29/marquee/pausing
Marquee State Transition Updates
2 parents b094c4c + b3fbb0f commit e648750

12 files changed

+430
-116
lines changed

components/Marquee/samples/Dependencies.props

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,21 @@
1111
<Project>
1212
<!-- WinUI 2 / UWP -->
1313
<ItemGroup Condition="'$(IsUwp)' == 'true'">
14-
<!-- <PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.2"/> -->
14+
<PackageReference Include="CommunityToolkit.Uwp.Behaviors" Version="8.2.250402"/>
1515
</ItemGroup>
1616

1717
<!-- WinUI 2 / Uno -->
1818
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '2'">
19-
<!-- <PackageReference Include="Uno.Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.11"/> -->
19+
<PackageReference Include="Uno.Microsoft.Toolkit.Uwp.UI.Behaviors" Version="7.1.11"/>
2020
</ItemGroup>
2121

2222
<!-- WinUI 3 / WinAppSdk -->
2323
<ItemGroup Condition="'$(IsWinAppSdk)' == 'true'">
24-
<!-- <PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.2"/> -->
24+
<PackageReference Include="CommunityToolkit.WinUI.Behaviors" Version="8.2.250402"/>
2525
</ItemGroup>
2626

2727
<!-- WinUI 3 / Uno -->
2828
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '3'">
29-
<!-- <PackageReference Include="Uno.CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.100-dev.15.g12261e2626"/> -->
29+
<PackageReference Include="Uno.CommunityToolkit.WinUI.UI.Behaviors" Version="7.1.204"/>
3030
</ItemGroup>
3131
</Project>

components/Marquee/samples/Marquee.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ icon: Assets/Marquee.png
1515

1616
The Marquee control allows text or other content to scroll in a marquee fashion. The control is heavily templated and many changes can be made by modifying the style. The control can also be adjusted using the Speed, Behavior, RepeatBehavior, and Direction properties.
1717

18+
> [!Sample MarqueeTextSample]
19+
1820
## Speed
1921

2022
The speed property determines how quickly the content moves in pixels per second. The speed can be adjusted mid-animation and handled continously.
@@ -23,6 +25,8 @@ The speed property determines how quickly the content moves in pixels per second
2325

2426
The Marquee control has 3 behaviors
2527

28+
Default: `Ticker`
29+
2630
### Ticker
2731

2832
Ticker mode starts with all content off the screen then scrolls the content across across the screen. When the animation finishes in the mode no content will be on screen.
@@ -39,14 +43,34 @@ Looping mode will begin with the start of the content fully in frame then scroll
3943

4044
The repeat behavior determines how many times the marquee will loop before the animation finishes. It can be a number of iteration, a duration, or forever.
4145

46+
Default: `1x`
47+
4248
## Direction
4349

4450
The default direction is left, meaning the content 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.
4551

46-
> [!Sample MarqueeTextSample]
52+
Default: `Left`
53+
54+
## Speed
55+
56+
The speed property determines how quickly the content moves in pixels-per-second. The speed can be adjusted mid-animation and handled continously. Because the speed is in pixels per second the actual time it takes to scroll will depend on the size of the content. The content can also change size dynamically and the speed will remain constant.
57+
58+
Default: `32`
59+
60+
## AutoPlay
61+
62+
The AutoPlay property determines if the marquee will start animating when it is loaded, upon on size changes, or when the content changes. If set to false the marquee can be started manually by calling the `StartMarquee` method.
63+
64+
Default: `false`
4765

4866
## Non-Text Content
4967

5068
It is possible to use non-text content in the Marquee control. However templating must be used because the control will need to be duplicated for the looping animation.
5169

5270
> [!Sample MarqueeSample]
71+
72+
# Level Up with Behaviors
73+
74+
Use behaviors to triggers the Marquee on events
75+
76+
> [!Sample MarqueeBehaviorSample]
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<!-- 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. -->
2+
<Page x:Class="MarqueeExperiment.Samples.MarqueeBehaviorSample"
3+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5+
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
6+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
7+
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
8+
xmlns:local="MarqueeExperiment.Samples"
9+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
10+
xmlns:win="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
11+
mc:Ignorable="d">
12+
13+
<win:StackPanel Padding="16">
14+
<TextBlock FontWeight="Bold"
15+
Text="This Marquee will loop once when hovered." />
16+
<controls:Marquee x:Name="Loop1Marquee"
17+
Background="Transparent"
18+
Behavior="Ticker"
19+
Content="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
20+
FontSize="18"
21+
RepeatBehavior="1x"
22+
Speed="256">
23+
<interactivity:Interaction.Behaviors>
24+
<interactivity:EventTriggerBehavior EventName="PointerEntered"
25+
SourceObject="{Binding ElementName=Loop1Marquee}">
26+
<interactivity:CallMethodAction MethodName="StartMarquee"
27+
TargetObject="{Binding ElementName=Loop1Marquee}" />
28+
</interactivity:EventTriggerBehavior>
29+
</interactivity:Interaction.Behaviors>
30+
</controls:Marquee>
31+
32+
<TextBlock Margin="0,16,0,0"
33+
FontWeight="Bold"
34+
Text="This Marquee contains hyperlinks and will pause while hovered." />
35+
<controls:Marquee x:Name="MarqueeControl"
36+
AutoPlay="True"
37+
Background="Transparent"
38+
Behavior="Looping"
39+
FontSize="18"
40+
RepeatBehavior="Forever"
41+
Speed="96">
42+
<controls:Marquee.ContentTemplate>
43+
<DataTemplate>
44+
<StackPanel Spacing="4">
45+
<RichTextBlock>
46+
<Paragraph>
47+
<Run Text="Lorem ipsum dolor sit amet, " />
48+
<Hyperlink>consectetur adipiscing elit</Hyperlink>
49+
<Run Text=", sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " />
50+
<Hyperlink>Ut enim ad minim veniam</Hyperlink>
51+
<Run Text=", quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." />
52+
</Paragraph>
53+
</RichTextBlock>
54+
</StackPanel>
55+
</DataTemplate>
56+
</controls:Marquee.ContentTemplate>
57+
<interactivity:Interaction.Behaviors>
58+
<interactivity:EventTriggerBehavior EventName="PointerEntered"
59+
SourceObject="{Binding ElementName=MarqueeControl}">
60+
<interactivity:CallMethodAction MethodName="PauseMarquee"
61+
TargetObject="{Binding ElementName=MarqueeControl}" />
62+
</interactivity:EventTriggerBehavior>
63+
<interactivity:EventTriggerBehavior EventName="PointerExited"
64+
SourceObject="{Binding ElementName=MarqueeControl}">
65+
<interactivity:CallMethodAction MethodName="StartMarquee"
66+
TargetObject="{Binding ElementName=MarqueeControl}" />
67+
</interactivity:EventTriggerBehavior>
68+
</interactivity:Interaction.Behaviors>
69+
</controls:Marquee>
70+
</win:StackPanel>
71+
</Page>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace MarqueeExperiment.Samples;
6+
7+
[ToolkitSample(id: nameof(MarqueeBehaviorSample), "Marquee", description: "A control for scrolling content in a marquee fashion.")]
8+
public sealed partial class MarqueeBehaviorSample : Page
9+
{
10+
public MarqueeBehaviorSample()
11+
{
12+
this.InitializeComponent();
13+
}
14+
}

components/Marquee/samples/MarqueeSample.xaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- 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. -->
1+
<!-- 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. -->
22
<Page x:Class="MarqueeExperiment.Samples.MarqueeSample"
33
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
44
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@@ -9,7 +9,8 @@
99
mc:Ignorable="d">
1010

1111
<StackPanel Padding="16">
12-
<controls:Marquee Behavior="{x:Bind ConvertStringToMarqueeBehavior(MQBehavior), Mode=OneWay}"
12+
<controls:Marquee AutoPlay="True"
13+
Behavior="{x:Bind ConvertStringToMarqueeBehavior(MQBehavior), Mode=OneWay}"
1314
Content="{x:Bind Data}"
1415
Direction="{x:Bind ConvertStringToMarqueeDirection(MQDirection), Mode=OneWay}"
1516
FontSize="18"

components/Marquee/samples/MarqueeText.Samples.csproj

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,5 @@
66

77
<!-- Sets this up as a toolkit component's sample project -->
88
<Import Project="$(ToolingDirectory)\ToolkitComponent.SampleProject.props" />
9-
<ItemGroup>
10-
<Compile Update="MarqueeTextSample.xaml.cs">
11-
<DependentUpon>MarqueeTextSample.xaml</DependentUpon>
12-
</Compile>
13-
</ItemGroup>
14-
<ItemGroup>
15-
<Compile Update="MarqueeSample.xaml.cs">
16-
<DependentUpon>MarqueeSample.xaml</DependentUpon>
17-
</Compile>
18-
</ItemGroup>
199

2010
</Project>
Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- 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. -->
1+
<!-- 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. -->
22
<Page x:Class="MarqueeExperiment.Samples.MarqueeTextSample"
33
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
44
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@@ -8,12 +8,24 @@
88
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
99
mc:Ignorable="d">
1010

11-
<StackPanel Padding="16">
12-
<controls:Marquee Behavior="{x:Bind ConvertStringToMarqueeBehavior(MQBehavior), Mode=OneWay}"
11+
<StackPanel Padding="16"
12+
Spacing="8">
13+
<controls:Marquee x:Name="MarqueeControl"
14+
AutoPlay="{x:Bind MQAuto, Mode=OneWay}"
15+
Behavior="{x:Bind ConvertStringToMarqueeBehavior(MQBehavior), Mode=OneWay}"
1316
Content="{x:Bind MQText, Mode=OneWay}"
1417
Direction="{x:Bind ConvertStringToMarqueeDirection(MQDirection), Mode=OneWay}"
1518
FontSize="18"
1619
RepeatBehavior="Forever"
1720
Speed="{x:Bind MQSpeed, Mode=OneWay}" />
21+
22+
<Button Click="StartMarquee_Click"
23+
Content="Start Marquee" />
24+
<Button Click="StopMarquee_Click"
25+
Content="Stop Marquee" />
26+
<Button Click="PauseMarquee_Click"
27+
Content="Pause Marquee" />
28+
<Button Click="ResumeMarquee_Click"
29+
Content="Resume Marquee" />
1830
</StackPanel>
1931
</Page>

components/Marquee/samples/MarqueeTextSample.xaml.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace MarqueeExperiment.Samples;
1616
#else
1717
[ToolkitSampleMultiChoiceOption("MQBehavior", "Ticker", "Looping", Title = "Marquee Behavior")]
1818
#endif
19+
[ToolkitSampleBoolOption("MQAuto", true, Title = "Auto Play")]
1920
public sealed partial class MarqueeTextSample : Page
2021
{
2122
public MarqueeTextSample()
@@ -41,4 +42,12 @@ public MarqueeTextSample()
4142
"Down" => MarqueeDirection.Down,
4243
_ => throw new System.NotImplementedException(),
4344
};
45+
46+
private void StartMarquee_Click(object sender, RoutedEventArgs e) => MarqueeControl.StartMarquee();
47+
48+
private void StopMarquee_Click(object sender, RoutedEventArgs e) => MarqueeControl.StopMarquee();
49+
50+
private void ResumeMarquee_Click(object sender, RoutedEventArgs e) => MarqueeControl.ResumeMarquee();
51+
52+
private void PauseMarquee_Click(object sender, RoutedEventArgs e) => MarqueeControl.PauseMarquee();
4453
}

components/Marquee/src/Marquee.Events.cs

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,23 @@ public partial class Marquee
1212
/// <summary>
1313
/// Event raised when the Marquee begins scrolling.
1414
/// </summary>
15-
public event EventHandler? MarqueeBegan;
15+
public event EventHandler? MarqueeStarted;
1616

1717
/// <summary>
18-
/// Event raised when the Marquee stops scrolling for any reason.
18+
/// Event raised when the Marquee is stopped manually or completed.
1919
/// </summary>
2020
public event EventHandler? MarqueeStopped;
2121

22+
/// <summary>
23+
/// Event raised when the Marquee is resumed from a pause.
24+
/// </summary>
25+
public event EventHandler? MarqueeResumed;
26+
27+
/// <summary>
28+
/// Event raised when the Marquee is paused.
29+
/// </summary>
30+
public event EventHandler? MarqueePaused;
31+
2232
/// <summary>
2333
/// Event raised when the Marquee completes scrolling.
2434
/// </summary>
@@ -28,18 +38,36 @@ private void Marquee_Loaded(object sender, RoutedEventArgs e)
2838
{
2939
// While loaded, detach the loaded event and attach the unloaded event
3040
this.Loaded -= this.Marquee_Loaded;
31-
this.Unloaded += Marquee_Unloaded;
41+
this.Unloaded += this.Marquee_Unloaded;
3242

3343
// Attach other events
3444
if (_marqueeContainer is not null)
3545
{
3646
_marqueeContainer.SizeChanged += Container_SizeChanged;
3747
}
3848

49+
if (_segment1 is not null)
50+
{
51+
_segment1.SizeChanged += Segment_SizeChanged;
52+
}
53+
3954
if (_marqueeStoryboard is not null)
4055
{
4156
_marqueeStoryboard.Completed += StoryBoard_Completed;
4257
}
58+
59+
// The size may have channged while unloaded.
60+
// Clip the marquee
61+
ClipMarquee();
62+
63+
// Setup the animation
64+
UpdateMarquee(false);
65+
66+
// The marquee should run when loaded if auto play is enabled
67+
if (AutoPlay)
68+
{
69+
StartMarquee();
70+
}
4371
}
4472

4573
private void Marquee_Unloaded(object sender, RoutedEventArgs e)
@@ -53,6 +81,11 @@ private void Marquee_Unloaded(object sender, RoutedEventArgs e)
5381
_marqueeContainer.SizeChanged -= Container_SizeChanged;
5482
}
5583

84+
if (_segment1 is not null)
85+
{
86+
_segment1.SizeChanged -= Segment_SizeChanged;
87+
}
88+
5689
if (_marqueeStoryboard is not null)
5790
{
5891
_marqueeStoryboard.Completed -= StoryBoard_Completed;
@@ -62,35 +95,41 @@ private void Marquee_Unloaded(object sender, RoutedEventArgs e)
6295
private void Container_SizeChanged(object sender, SizeChangedEventArgs e)
6396
{
6497
if (_marqueeContainer is null)
65-
{
6698
return;
67-
}
6899

69-
// Clip the marquee within its bounds
70-
_marqueeContainer.Clip = new RectangleGeometry
71-
{
72-
Rect = new Rect(0, 0, e.NewSize.Width, e.NewSize.Height)
73-
};
100+
// Clip the marquee
101+
ClipMarquee(e.NewSize.Width, e.NewSize.Height);
102+
103+
// Update animation on the fly
104+
UpdateMarquee(true);
74105

75106
// The marquee should run when the size changes in case the text gets cutoff
76-
StartMarquee();
107+
// and auto play is enabled.
108+
if (AutoPlay)
109+
{
110+
StartMarquee();
111+
}
77112
}
78113

79114
private void Segment_SizeChanged(object sender, SizeChangedEventArgs e)
80115
{
81116
if (_segment1 is null)
82-
{
83117
return;
84-
}
118+
119+
if (_marqueeContainer is null)
120+
return;
121+
122+
// Cap the height of the container to the segment height
123+
_marqueeContainer.Height = _segment1.ActualHeight;
85124

86125
// If the segment size changes, we need to update the storyboard,
87126
// and seek to the correct position to maintain a smooth animation.
88-
UpdateAnimation(true);
127+
UpdateMarquee(true);
89128
}
90129

91130
private void StoryBoard_Completed(object? sender, object e)
92131
{
93-
StopMarquee(true);
132+
StopMarquee();
94133
MarqueeCompleted?.Invoke(this, EventArgs.Empty);
95134
}
96135
}

0 commit comments

Comments
 (0)