WPF字幕文本动画在其他控件中滚动

WPF字幕文本动画在其他控件中滚动

问题描述:

我在下面给出的带有XAML的窗口中实施了this question的解决方案。我试图做一个标签滚动字幕文本效果:WPF字幕文本动画在其他控件中滚动

<Window x:Class="WpfMarqueeText.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:wpfMarqueeText="clr-namespace:WpfMarqueeText" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="200"/> 
      <RowDefinition Height="*"/> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="500"/> 
      <ColumnDefinition Width="*"/> 
     </Grid.ColumnDefinitions> 

     <Grid Grid.Row="0" Grid.Column="0" Background="Aqua"> 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition Width="200"/> 
       <ColumnDefinition Width="300"/> 
      </Grid.ColumnDefinitions> 

      <Ellipse Grid.Column="0" Margin="5,3,5,3" Fill="#b933ad"/> 
      <Label Grid.Column="0" Content="Z" Foreground="White" FontFamily="HelveticaBold" FontSize="150" FontWeight="Bold" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5,3,5,3"/> 

      <Grid Grid.Column="1"> 
       <Grid.RowDefinitions> 
        <RowDefinition Height="Auto"/> 
        <RowDefinition Height="*"/> 
       </Grid.RowDefinitions> 

       <Grid Grid.Row="0"> 
        <Grid.RowDefinitions> 
         <RowDefinition Height="Auto"/> 
         <RowDefinition Height="Auto"/> 
        </Grid.RowDefinitions> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="Auto"/> 
         <ColumnDefinition Width="*"/> 
        </Grid.ColumnDefinitions> 

        <Label Grid.Row="0" Grid.Column="0" Content="Some Info:" FontFamily="HelveticaBold" FontSize="18" FontWeight="Bold" Margin="5,3,5,3"/> 

        <StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal" x:Name="stack"> 
         <StackPanel.Resources> 
          <wpfMarqueeText: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}"> 
          <Label FontFamily="HelveticaBold" FontSize="18" Margin="5,3,5,3" x:Name="Label1" Content="Blah blah blah" Canvas.Left="0"/> 
          <Label Name="Label2" Content="{Binding Content, ElementName=Label1}" FontFamily="HelveticaBold" FontSize="18" Margin="5,3,5,3" Canvas.Left="{Binding ActualWidth, ElementName=stack}"/> 
         </Canvas> 

        </StackPanel> 
       </Grid> 
      </Grid> 
     </Grid> 
    </Grid> 
</Window> 

你也必须定义NegatingConverter类的代码隐藏:

public class NegatingConverter : IValueConverter 
{ 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (value is double) 
     { 
      return -((double)value); 
     } 
     return value; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (value is double) 
     { 
      return +(double)value; 
     } 
     return value; 
    } 
} 

这将产生预期的效应,但是文动画在滚动中看到下面的图片(对不起,我没有足够的代表,发布图片)的其他用户界面元素:

http://tinypic.com/r/df8zeu/9 http://tinypic.com/r/2inc3r/9

那么,有什么方法可以修复动画,以便文本只在它所包含的网格列的边界内或在标签本身的边界内滚动?谢谢你的帮助!

+0

http://www.codeproject.com/Articles/48267/Making-a-Simple-Marquee-Text-Control-Drip-Animatio应该会帮助你 – Akanksha

+0

真棒,感谢你发布这个。我会尽力在我的项目中实现这一点。 – lunaa

Akanksha为响应我的OP链接的文章展示了如何创建一个产生干净的滚动文本效果的用户控件。您还可以指定4个不同的滚动方向,左侧< - >向右并向上< - >向下。我在这里给我的实现为他人:

XAML为MarqueeTextUserControl:

<UserControl x:Class="AaronLuna.Common.UI.UserControls.MarqueeTextUserControl" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     mc:Ignorable="d" Loaded="UserControl_Loaded"> 

    <Canvas ClipToBounds="True" Name="CanvasMain"> 
     <TextBlock Name="TextBlockMain"/> 
    </Canvas> 

</UserControl> 

代码MarqueeTextUserControl:

namespace AaronLuna.Common.UI.UserControls 
{   
    public partial class MarqueeTextUserControl 
    { 
     public MarqueeTextUserControl() 
     { 
      InitializeComponent(); 
      CanvasMain.Height = Height; 
      CanvasMain.Width = Width; 
     } 

     public ScrollDirection ScrollDirection { get; set; } 
     public double ScrollDurationInSeconds { get; set; } 
     public String Text { set { TextBlockMain.Text = value; }} 

     private void UserControl_Loaded(object sender, RoutedEventArgs e) 
     { 
      ScrollText(ScrollDirection); 
     } 

     public void ScrollText(ScrollDirection scrollDirection) 
     { 
      switch (scrollDirection) 
      { 
       case ScrollDirection.LeftToRight: 
        LeftToRightMarquee(); 
        break; 
       case ScrollDirection.RightToLeft: 
        RightToLeftMarquee(); 
        break; 
       case ScrollDirection.TopToBottom: 
        TopToBottomMarquee(); 
        break; 
       case ScrollDirection.BottomToTop: 
        BottomToTopMarquee(); 
        break; 
      } 
     } 

     private void LeftToRightMarquee() 
     { 
      double height = CanvasMain.ActualHeight - TextBlockMain.ActualHeight; 
      TextBlockMain.Margin = new Thickness(0, height/2, 0, 0); 

      var doubleAnimation = new DoubleAnimation 
      { 
       From = -TextBlockMain.ActualWidth, 
       To = CanvasMain.ActualWidth, 
       RepeatBehavior = RepeatBehavior.Forever, 
       Duration = new Duration(TimeSpan.FromSeconds(ScrollDurationInSeconds)) 
      }; 

      TextBlockMain.BeginAnimation(Canvas.LeftProperty, doubleAnimation); 
     } 

     private void RightToLeftMarquee() 
     { 
      double height = CanvasMain.ActualHeight - TextBlockMain.ActualHeight; 
      TextBlockMain.Margin = new Thickness(0, height/2, 0, 0); 

      var doubleAnimation = new DoubleAnimation 
      { 
       From = -TextBlockMain.ActualWidth, 
       To = CanvasMain.ActualWidth, 
       RepeatBehavior = RepeatBehavior.Forever, 
       Duration = new Duration(TimeSpan.FromSeconds(ScrollDurationInSeconds)) 
      }; 

      TextBlockMain.BeginAnimation(Canvas.RightProperty, doubleAnimation); 
     } 

     private void TopToBottomMarquee() 
     { 
      double width = CanvasMain.ActualWidth - TextBlockMain.ActualWidth; 
      TextBlockMain.Margin = new Thickness(width/2, 0, 0, 0); 

      var doubleAnimation = new DoubleAnimation 
      { 
       From = -TextBlockMain.ActualHeight, 
       To = CanvasMain.ActualHeight, 
       RepeatBehavior = RepeatBehavior.Forever, 
       Duration = new Duration(TimeSpan.FromSeconds(ScrollDurationInSeconds)) 
      }; 

      TextBlockMain.BeginAnimation(Canvas.TopProperty, doubleAnimation); 
     } 

     private void BottomToTopMarquee() 
     { 
      double width = CanvasMain.ActualWidth - TextBlockMain.ActualWidth; 
      TextBlockMain.Margin = new Thickness(width/2, 0, 0, 0); 

      var doubleAnimation = new DoubleAnimation 
      { 
       From = -TextBlockMain.ActualHeight, 
       To = CanvasMain.ActualHeight, 
       RepeatBehavior = RepeatBehavior.Forever, 
       Duration = new Duration(TimeSpan.FromSeconds(ScrollDurationInSeconds)) 
      }; 

      TextBlockMain.BeginAnimation(Canvas.BottomProperty, doubleAnimation); 
     } 
    } 

    public enum ScrollDirection 
    { 
     LeftToRight, 
     RightToLeft, 
     TopToBottom, 
     BottomToTop 
    } 
} 

客户XAML:

<UserControl x:Class="MarqueeTextExampleUserControl" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:userControls="clr-namespace:AaronLuna.Common.UI.UserControls;assembly=AaronLuna.Common" 
     mc:Ignorable="d"> 

    <DockPanel> 
     <Label Content="Some Info:"/> 
     <userControls:MarqueeTextUserControl x:Name="MarqueeTextBlock"/> 
    </DockPanel> 

</UserControl> 

客户端代码:

MarqueeTextBlock.Text = "Blah blah blah"; 
MarqueeTextBlock.ScrollDirection = ScrollDirection.RightToLeft; 
MarqueeTextBlock.ScrollDurationInSeconds = 10; 

这是一个快速和肮脏的解决方案:

更改Label

<Label Grid.Row="0" Grid.Column="0" Content="Some Info:" FontFamily="HelveticaBold" FontSize="18" FontWeight="Bold" Margin="5,3,5,3" Panel.ZIndex="99" Background="Aqua"/> 

Panel.ZIndex带来Label前面。并使Background不透明给出所需的外观。边界仍然不完美,但是这应该给你一个关于如何处理图层的线索

+0

谢谢!我想尝试类似的东西,但将ZIndex应用于错误的XAML元素。 – lunaa