2013-03-10 21 views
14

Я могу прокручивать текст с помощью TranslateTransform, но когда анимация близка к завершению, я хотел бы, чтобы она начиналась снова. Как змея :)WPF Marquee Text Animation

Это то, что я получил:

<StackPanel Orientation="Horizontal" Margin="0,0,0,0"> 
    <StackPanel.RenderTransform> 
     <TranslateTransform x:Name="transferCurreny" X="-40"/> 
    </StackPanel.RenderTransform> 
    <StackPanel.Triggers> 
     <EventTrigger RoutedEvent="StackPanel.Loaded"> 
      <BeginStoryboard> 
       <Storyboard> 
        <DoubleAnimation From="0" To="-900" Duration="00:00:10" 
         Storyboard.TargetProperty="X" 
         Storyboard.TargetName="transferCurreny" 
         RepeatBehavior="Forever"/> 
       </Storyboard> 
      </BeginStoryboard> 
     </EventTrigger> 
    </StackPanel.Triggers> 
    <TextBlock FontSize="25" x:Name="txtKron" Margin="10,0,7,0"/> 
</StackPanel> 

Это то, что я хотел:

enter image description here

+0

Что вопрос? Какое желаемое поведение, какое поведение вы получаете? –

+0

Вопрос; я хочу выделить текст, но как змея – meymetkaplan

+0

Я до сих пор не понимаю. Вы можете нарисовать картину? Или указать нам место, где вы видели этот эффект раньше? –

ответ

12

Что-то вроде этого следует сделать трюк.

Вы можете добавить Canvas к StackPanel с 2 TextBlocks один набор в положение 0 и один набор на ActualWidth из StackPanel, затем, когда первый блок текста идет закадровый другой блок выйдет в поле зрения.

Причина я Canvas потому, что Canvas является единственным элементом, который фактически поддерживает ClipToBounds="false" это позволяет второй TextBlock быть виден, даже если его помещают вне пределы Canvas сам

Нам также нужна IValueConverter, чтобы получить правильное отрицательное значение, если вы хотите прокручивать справа налево.

Я также добавил триггер события на SizeChanged, поэтому, если окно изменено, значения анимации будут корректно обновляться.

Код:

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> 

Результат:

enter image description hereenter image description here

Edit: слева направо

<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

Привет Это действительно здорово. Я работаю над этим buttom to top :), но у меня есть одна проблема об этом; , когда первый блок вверх (на самом деле одно изображение), он будет top = 0, но изображение почти top = 50, я не исправил это. Спасибо! – meymetkaplan

+0

Здесь есть проблема - анимация не начинается. Я исправил его в коде, добавив событие Loaded и в нем: Storyboard sb = (Storyboard) this.stack.FindResource («слайд»); stack.Dispatcher.BeginInvoke (DispatcherPriority.Loaded, new Action (() => { sb.Begin(); })); –

+0

Мы можем использовать этот же код для изображения. спасибо sa_ddam – Sagotharan

3

В приведенном выше ответе не производится непрерывный прокрутка. Вот код для непрерывного плавного прокрутки.

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 код Сзади:

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

Ницца. Работает хорошо! –