【问题标题】:WPF Marquee Text AnimationWPF 选取框文本动画
【发布时间】:2013-02-25 17:15:39
【问题描述】:

我可以使用TranslateTransform 滚动文本,但是当动画接近完成时,我希望它重新开始。像一条蛇:)

这就是我所拥有的:

<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>

这就是我想要的:

【问题讨论】:

  • 有什么问题?期望的行为是什么,你得到的行为是什么?
  • 问题是;我想选框文字,但喜欢蛇
  • 我还是不明白。你能画一幅画吗?或者向我们指出您以前见过这种效果的地方?
  • +1 并为清晰起见进行了编辑。我不认为你可以用一个&lt;TextBlock&gt; 来做到这一点,你可能需要两个或更多。我试着把一些东西放在一起,但对我来说,翻译动画只会显示动画开始时屏幕上可见的东西。使用两个 TextBlock 有点没用,需要一个在动画开始时离开屏幕。

标签: wpf animation marquee


【解决方案1】:

这样的事情应该可以解决问题。

您可以将Canvas 添加到StackPanel,其中2 个TextBlocks 一个设置为位置0,一个设置为StackPanel 的ActualWidth,然后当第一块文本离开屏幕时另一个块将进入视野。

我使用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>

结果:

编辑:从左到右

 <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,但图像几乎是顶部 = 50,我没有解决这个问题。谢谢!
  • 从动画To属性中移除转换器并将其添加到最后一个TextBlock的Canvas.Left属性中,上面添加示例
  • 文本过长无法放入TextBlock怎么办?然后两个 TextBlock 重叠,事情变得丑陋。
  • ConvertBack方法不应该和NegatingConverter中的Convert一样吗?
  • 嗨,这很好用,但是当文本很长时会有重叠。你知道怎么解决吗?
【解决方案2】:

上述答案中的代码不会产生连续滚动。这是连续平滑滚动的代码。

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

【讨论】:

    【解决方案3】:

    扩展answer of sa_ddam213,这是对第一个动画(从右到左)的修改。这适用于长字符串。 :)

    <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>
    

    【讨论】:

      【解决方案4】:

      为了使字符串比元素长,并隐藏溢出元素的文本,我进一步修改了以前的答案。

      要直接使用这个,首先创建一个名为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>
      

      此窗口的 c# 代码:

      <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>
      

      【讨论】:

      • 看起来您是第二次粘贴您的 xaml 而不是发布 C# 代码,您可以改用 C# 代码进行编辑吗? MarqueeMargin 和 NegMarqueeMargin 的 C# 也丢失了
      猜你喜欢
      • 2022-01-23
      • 2011-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-11
      • 1970-01-01
      • 2021-01-31
      • 2011-01-16
      相关资源
      最近更新 更多