Animación de texto WPF Marquee

Puedo desplazar texto con TranslateTransform pero cuando la animación está a punto de terminar, me gustaría que comience de nuevo. Como una serpiente 🙂

Esto es lo que tengo:

                

Esto es lo que me gustaría:

enter image description here

Algo como esto debería hacer el truco.

Puede agregar un Canvas al StackPanel con 2 TextBlocks uno configurado en la posición 0 y uno configurado en el ActualWidth del StackPanel , y cuando el primer bloque de texto pase a estar fuera de pantalla, el otro bloque aparecerá en la vista.

La razón por la que utilicé Canvas es porque Canvas es el único elemento que realmente admite ClipToBounds="false" esto permite que el 2nd TextBlock sea ​​visible incluso si se coloca fuera de los límites del Canvas

También necesitamos un IValueConverter para obtener el valor negativo correcto si desea desplazarse de derecha a izquierda.

También agregué un activador de evento en SizeChanged por lo que si la ventana SizeChanged tamaño, los valores de la animación se actualizarán correctamente.

Código:

 namespace WpfApplication9 { ///  /// Interaction logic for MainWindow.xaml ///  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:

                          

Resultado:

enter image description hereenter image description here

Editar: de izquierda a derecha

                         

El código en la respuesta anterior no produce desplazamiento continuo. Aquí está el código para desplazamiento suave continuo.

XAML:

         

Código VB detrás:

 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 

Extendiendo la respuesta de sa_ddam213 , esta es una revisión de la primera animación (de derecha a izquierda). Esto funcionará para cadenas largas. 🙂