WPF Marquee Text Animation

后端 未结 4 1125
醉梦人生
醉梦人生 2020-11-27 18:01

I can scroll text with TranslateTransform but when the animation is close to finishing I\'d like it to begin again. Like a snake :)

This is what I\'ve g

相关标签:
4条回答
  • 2020-11-27 18:29

    Exteding the answer of sa_ddam213, this is a revise of the first animation(Right to Left). This will work for long strings. :)

    <StackPanel Orientation="Horizontal"
                        x:Name="stack" 
                        Grid.Column="0"
                        Margin="0"                        >
    
                <StackPanel.Resources>
                    <local1:NegatingConverter x:Key="NegatingConverter" />
                    <Storyboard x:Key="slide">
                        <DoubleAnimation From="{Binding ActualWidth, ElementName=stack}" 
                                         To="{Binding ActualWidth, ElementName=txtKron, Converter={StaticResource NegatingConverter}}" 
                                         Duration="00:00:30"
                                         Storyboard.TargetProperty="X"
                                         Storyboard.TargetName="transferCurreny2"
                                         RepeatBehavior="Forever"/>
                    </Storyboard>
                </StackPanel.Resources>
    
                <Label Content="{Binding Path=RSSFeed}" 
                           x:Name="txtKron" 
                           Canvas.Left="0"
                           Foreground="#E9D460"
                           Padding="0"
                           Margin="0"
                           VerticalAlignment="Center">
    
                    <Label.Triggers>
                        <EventTrigger RoutedEvent="Label.Loaded">
                            <BeginStoryboard Storyboard="{StaticResource slide}"/>
                        </EventTrigger>
                        <EventTrigger RoutedEvent="Label.SizeChanged">
                            <BeginStoryboard Storyboard="{StaticResource slide}"/>
                        </EventTrigger>
                    </Label.Triggers>
    
                    <Label.RenderTransform>
                        <TranslateTransform x:Name="transferCurreny2" X="0"/>
                    </Label.RenderTransform>
                </Label>
    
            </StackPanel>
    
    0 讨论(0)
  • 2020-11-27 18:31

    The code in above answer does not produce continuous scroll. Here is the code for continuous smooth scroll.

    XAML:

    <Window x:Class="Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
        <Grid>
            <Canvas Margin="6,83,9,0" Name="ViewingBox" Background="YellowGreen" Height="35" VerticalAlignment="Top">
                <Label Canvas.Left="263" Canvas.Top="-2" Height="49" Name="BoxOne" FontSize="20">I need breakfast.</Label>
                <Label Canvas.Left="263" Canvas.Top="-2" Height="49" HorizontalAlignment="Stretch" Name="BoxTwo" VerticalAlignment="Top" FontSize="20">You can have oranges and egg.</Label>
            </Canvas>   
        </Grid>
    </Window>
    

    VB Code Behind:

    Imports System.Windows.Media.Animation
    
    Public Enum Texts
        BoxOne
        BoxTwo
    End Enum
    
    Class Window1
        Private dubAnim As New DoubleAnimation()
        Private dubAnim2 As New DoubleAnimation()
        Private NewsTimer As New Windows.Threading.DispatcherTimer()
        Dim leadText As Texts = Texts.BoxOne
    
        Private Sub Window1_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
            dubAnim.From = ViewingBox.ActualWidth
            dubAnim.To = -BoxOne.ActualWidth
            dubAnim.SpeedRatio = 0.05
            AddHandler dubAnim.Completed, AddressOf dubAnim_Completed
            Timeline.SetDesiredFrameRate(dubAnim, 320)
            BoxOne.BeginAnimation(Canvas.LeftProperty, dubAnim)
    
            dubAnim2.From = ViewingBox.ActualWidth
            dubAnim2.To = -BoxTwo.ActualWidth
            dubAnim2.SpeedRatio = 0.05
            Timeline.SetDesiredFrameRate(dubAnim2, 320)
            AddHandler dubAnim2.Completed, AddressOf dubAnim2_Completed
    
            AddHandler NewsTimer.Tick, AddressOf NewsTimer_Tick
            NewsTimer.Interval = New TimeSpan(0, 0, 0.9)
            NewsTimer.Start()
        End Sub
    
        Private Sub NewsTimer_Tick(ByVal sender As Object, ByVal e As EventArgs)
            Dim BoxOneLocation As Point = BoxOne.TranslatePoint(New Point(0, 0), ViewingBox)
            Dim BoxTwoLocation As Point = BoxTwo.TranslatePoint(New Point(0, 0), ViewingBox)
    
            If leadText = Texts.BoxOne Then
                Dim loc As Double = BoxOneLocation.X + BoxOne.ActualWidth
                If loc < ViewingBox.ActualWidth / 1.5 Then
                    BoxTwo.BeginAnimation(Canvas.LeftProperty, dubAnim2)
                    NewsTimer.Stop()
                End If
            Else
                Dim loc As Double = BoxTwoLocation.X + BoxTwo.ActualWidth
                If loc < ViewingBox.ActualWidth / 1.5 Then
                    BoxOne.BeginAnimation(Canvas.LeftProperty, dubAnim)
                    NewsTimer.Stop()
                End If
            End If
        End Sub
    
        Private Sub dubAnim_Completed(ByVal sender As Object, ByVal e As EventArgs)
            leadText = Texts.BoxTwo
            NewsTimer.Start()
        End Sub
    
        Private Sub dubAnim2_Completed(ByVal sender As Object, ByVal e As EventArgs)
            leadText = Texts.BoxOne
            NewsTimer.Start()
        End Sub
    End Class
    
    0 讨论(0)
  • 2020-11-27 18:33

    Something like this should do the trick.

    You can add a Canvas to the StackPanel with 2 TextBlocks one set to position 0 and one set to the ActualWidth of the StackPanel, then when the first block of text goes offscreen the other block will come into view.

    The reason I used Canvas is because Canvas is the only element that actually supports ClipToBounds="false" this allows the 2nd TextBlock to be visible even if its placed outside the bounds of the Canvas itself

    We also need a IValueConverter to get the correct negative value if you want to scroll from right to left.

    I also added event trigger on SizeChanged so if the window is resized the animation values will update correctly.

    Code:

    namespace WpfApplication9
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
    
            public MainWindow()
            {
                InitializeComponent();
            }
        }
    
        public class NegatingConverter : IValueConverter
        {
    
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (value is double)
                {
                    return -((double)value);
                }
                return value;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (value is double)
                {
                    return +(double)value;
                }
                return value;
            }
        }
    }
    

    Xaml:

    <Window x:Class="WpfApplication9.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication9"
            Title="MainWindow" Height="83" Width="222" Name="UI" Tag="Tol Level">
        <StackPanel Orientation="Horizontal" x:Name="stack">
            <StackPanel.Resources>
                <local:NegatingConverter x:Key="NegatingConverter" />
                <Storyboard x:Key="slide">
                    <DoubleAnimation From="0" To="{Binding Width, ElementName=canvas, Converter={StaticResource NegatingConverter}}" Duration="00:00:10"
                          Storyboard.TargetProperty="X"
                          Storyboard.TargetName="transferCurreny"
                          RepeatBehavior="Forever"/>
                </Storyboard>
            </StackPanel.Resources>
            <StackPanel.RenderTransform>
                <TranslateTransform x:Name="transferCurreny" X="0"/>
            </StackPanel.RenderTransform>
            <StackPanel.Triggers>
                <EventTrigger RoutedEvent="StackPanel.Loaded">
                    <BeginStoryboard Storyboard="{StaticResource slide}" />
                </EventTrigger>
                <EventTrigger RoutedEvent="StackPanel.SizeChanged">
                    <BeginStoryboard Storyboard="{StaticResource slide}" />
                </EventTrigger>
            </StackPanel.Triggers>
            <Canvas x:Name="canvas" Width="{Binding ActualWidth, ElementName=stack}">
                <TextBlock Text="StackOverflow" FontSize="25"  x:Name="txtKron" Canvas.Left="0"/>
                <TextBlock Text="{Binding Text, ElementName=txtKron}" FontSize="25" Canvas.Left="{Binding Width, ElementName=canvas}"/>
            </Canvas>
        </StackPanel>
    </Window>
    

    Result:

    enter image description here enter image description here

    Edit: Left to Right

     <StackPanel Orientation="Horizontal" x:Name="stack">
            <StackPanel.Resources>
                <local:NegatingConverter x:Key="NegatingConverter" />
                <Storyboard x:Key="slide">
                    <DoubleAnimation From="0" To="{Binding Width, ElementName=canvas}" Duration="00:00:10"
                          Storyboard.TargetProperty="X"
                          Storyboard.TargetName="transferCurreny"
                          RepeatBehavior="Forever"/>
                </Storyboard>
            </StackPanel.Resources>
            <StackPanel.RenderTransform>
                <TranslateTransform x:Name="transferCurreny" X="0"/>
            </StackPanel.RenderTransform>
            <StackPanel.Triggers>
                <EventTrigger RoutedEvent="StackPanel.Loaded">
                    <BeginStoryboard Storyboard="{StaticResource slide}" />
                </EventTrigger>
                <EventTrigger RoutedEvent="StackPanel.SizeChanged">
                    <BeginStoryboard Storyboard="{StaticResource slide}" />
                </EventTrigger>
            </StackPanel.Triggers>
            <Canvas x:Name="canvas" Width="{Binding ActualWidth, ElementName=stack}">
                <TextBlock Text="StackOverflow" FontSize="25"  x:Name="txtKron" Canvas.Left="0"/>
                <TextBlock Text="{Binding Text, ElementName=txtKron}" FontSize="25" Canvas.Left="{Binding Width, ElementName=canvas, Converter={StaticResource NegatingConverter}}"/>
            </Canvas>
        </StackPanel>
    
    0 讨论(0)
  • 2020-11-27 18:55

    To make this work for strings longer than the element, and hide the text which is overflowing out of the element, I modified previous answers further.

    To use this directly, first create a project called WpfApp1

    xaml:

    <Window x:Class="WpfApp1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Grid>
    
            <Border Width="200" HorizontalAlignment="Center" VerticalAlignment="Center" Height="25" ClipToBounds="True" BorderThickness="1.5" BorderBrush="Red">
                <Border x:Name="stack">
                    <Border.Resources>
                        <local:NegatingConverter x:Key="NegatingConverter" />
                        <local:MarqueeMargin x:Key="MarqueeMargin" />
                        <local:NegMarqueeMargin x:Key="NegMarqueeMargin" />
    
                        <Storyboard x:Key="slide">
                            <DoubleAnimation From="0" To="{Binding ActualWidth, ElementName=txt_scroll, Converter={StaticResource NegMarqueeMargin}}" Duration="00:00:2"
                              Storyboard.TargetProperty="X"
                              Storyboard.TargetName="transferCurreny"
                              RepeatBehavior="Forever"/>
                        </Storyboard>
                    </Border.Resources>
                    <Border.RenderTransform>
                        <TranslateTransform x:Name="transferCurreny" X="0"/>
                    </Border.RenderTransform>
                    <Border.Triggers>
                        <EventTrigger RoutedEvent="StackPanel.Loaded">
                            <BeginStoryboard Storyboard="{StaticResource slide}" />
                        </EventTrigger>
                        <EventTrigger RoutedEvent="StackPanel.SizeChanged">
                            <BeginStoryboard Storyboard="{StaticResource slide}" />
                        </EventTrigger>
                    </Border.Triggers>
                    <Canvas Width="{Binding ActualWidth, ElementName=stack}">
                        <TextBlock Text="This text is too long to fit in the parent element." FontSize="15" Foreground="#F00" x:Name="txt_scroll" Canvas.Left="0"/>
                        <TextBlock Text="{Binding Text, ElementName=txt_scroll}" FontSize="15" Foreground="#F00" Canvas.Left="{Binding ActualWidth, ElementName=txt_scroll, Converter={StaticResource MarqueeMargin}}"/>
                    </Canvas>
                </Border>
            </Border>
    
        </Grid>
    </Window>
    

    the c# code for this window:

    <Window x:Class="WpfApp1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Grid>
    
            <Border Width="200" HorizontalAlignment="Center" VerticalAlignment="Center" Height="25" ClipToBounds="True" BorderThickness="1.5" BorderBrush="Red">
                <Border x:Name="moving_border">
                    <Border.Resources>
                        <local:NegatingConverter x:Key="NegatingConverter" />
                        <local:MarqueeMargin x:Key="MarqueeMargin" />
                        <local:NegMarqueeMargin x:Key="NegMarqueeMargin" />
    
                        <Storyboard x:Key="slide">
                            <DoubleAnimation From="0" To="{Binding ActualWidth, ElementName=txt_scroll, Converter={StaticResource NegMarqueeMargin}}" Duration="00:00:2"
                              Storyboard.TargetProperty="X"
                              Storyboard.TargetName="transferCurreny"
                              RepeatBehavior="Forever"/>
                        </Storyboard>
                    </Border.Resources>
                    <Border.RenderTransform>
                        <TranslateTransform x:Name="transferCurreny" X="0"/>
                    </Border.RenderTransform>
                    <Border.Triggers>
                        <EventTrigger RoutedEvent="Border.Loaded">
                            <BeginStoryboard Storyboard="{StaticResource slide}" />
                        </EventTrigger>
                        <EventTrigger RoutedEvent="Border.SizeChanged">
                            <BeginStoryboard Storyboard="{StaticResource slide}" />
                        </EventTrigger>
                    </Border.Triggers>
                    <Canvas Width="{Binding ActualWidth, ElementName=moving_border}">
                        <TextBlock Text="This text is too long to fit in the parent element." FontSize="15" Foreground="#F00" x:Name="txt_scroll" Canvas.Left="0"/>
                        <TextBlock Text="{Binding Text, ElementName=txt_scroll}" FontSize="15" Foreground="#F00" Canvas.Left="{Binding ActualWidth, ElementName=txt_scroll, Converter={StaticResource MarqueeMargin}}"/>
                    </Canvas>
                </Border>
            </Border>
    
        </Grid>
    </Window>
    
    0 讨论(0)
提交回复
热议问题