WPF字幕文本动画滚动浏览其他控件

时间:2016-07-25 04:38:12

标签: c# wpf

我在下面给出了XAML的窗口中实现了this question的解决方案。我正在尝试为标签创建滚动字幕文本效果:

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

这会产生所需的效果,但文本动画会滚动到其他UI元素上,如下图所示(抱歉,我没有足够的代表发布图像):

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

那么,有没有办法修复动画,以便文本只在包含在其中的网格列的边界内或在标签本身的边界内滚动?谢谢你的帮助!

2 个答案:

答案 0 :(得分:0)

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

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.ZIndexLabel带到前面。并使Background不透明可以提供所需的外观。边界仍然不完美,但这应该给你一个如何处理图层的线索

答案 1 :(得分:0)

Akanksha在回复我的OP时链接的文章展示了如何创建一个产生干净,滚动文本效果的用户控件。您还可以指定4个不同的滚动方向,左侧&lt; - &gt;正确和向上&lt; - &gt;下。我会在这里为其他人提供我的实施:

MarqueeTextUserControl的XAML:

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