WPF 选取框文本动画
Posted
技术标签:
【中文标题】WPF 选取框文本动画【英文标题】:WPF Marquee Text Animation 【发布时间】: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>
这就是我想要的:
【问题讨论】:
有什么问题?期望的行为是什么,你得到的行为是什么? 问题是;我想选框文字,但喜欢蛇 我还是不明白。你能画一幅画吗?或者向我们指出您以前见过这种效果的地方? 图片; postimage.org/image/k0x636tgx +1 并为清晰起见进行了编辑。我不认为你可以用一个<TextBlock>
来做到这一点,你可能需要两个或更多。我试着把一些东西放在一起,但对我来说,翻译动画只会显示动画开始时屏幕上可见的东西。使用两个 TextBlock 有点没用,需要一个在动画开始时离开屏幕。
【参考方案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="***" 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="***" 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# 也丢失了以上是关于WPF 选取框文本动画的主要内容,如果未能解决你的问题,请参考以下文章