2009-04-22 74 views
0

我有一些从this post on MSDN修改的滚动文本动画。不过,我有两个问题。滚动文本更新问题

首先是我需要能够定期更新文本。但是,当OnTick()触发时,我得到以下错误:“调用线程不能访问此对象,因为不同的线程拥有它。”我尝试了一些不同的东西,并发布了一个我尝试过的方法。

第二个是,我不需要滚动来回,我真的需要文字行为作为一个真正的选取和行进一个方向,内容不断流动,没有差距,即“abcdeabcde ...”而不是“abcde ”。这是否需要两个故事板与相同的文本一起运行,还是有另一种方法来实现这一点?

Storyboard storyboard = new Storyboard(); 
    Timer timer; 
    public void OnLoad(object sender, RoutedEventArgs e) 
    { 
     _presenter.OnViewReady(); 
     StartMarquee(); 
    } 
    public MyControl() 
    { 
     InitializeComponent(); 
     Loaded += OnLoad; 
     timer = new Timer(OnTick, null, 10000, 10000); 
    } 
    private void OnTick(object state) 
    { 
     storyboard.Stop(marqueeText); 
     storyboard = new Storyboard(); 
     marqueeText.Text = 
      "Fusce id massa sed tortor volutpat viverra. Mauris ut quam. Fusce iaculis magna at urna. In sed dui vitae quam faucibus ullamcorper. Donec hendrerit magna eget neque. Mauris sit amet risus dictum mauris ultricies ornare. Phasellus lectus leo, mattis eget, ultrices vel, suscipit eu, tellus. Integer ut enim. Suspendisse hendrerit mattis sem. Aenean interdum elementum libero. "; 
     StartMarquee(); 
    } 
    protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) 
    { 
     base.OnRenderSizeChanged(sizeInfo); 
     marqueeText.Text = 
      "Is it possible to create a marquee or scrolling text in WPF? Is it possible to create a marquee or scrolling text in WPF? Is it possible to create a marquee or scrolling text in WPF? Is it possible to create a marquee or scrolling text in WPF? Is it possible to create a marquee or scrolling text in WPF? Is it possible to create a marquee or scrolling text in WPF?"; 
    } 
    private void StartMarquee() 
    { 
     var canvas = CommonFunctions.FindVisualParent<Canvas>(marqueeText); 
     if (marqueeText.ActualWidth < canvas.ActualWidth) return; 
     var duration = new Duration(TimeSpan.FromSeconds(marqueeText.ActualWidth/60)); 
     var animation = new DoubleAnimation(-marqueeText.ActualWidth, canvas.ActualWidth, duration); 
     animation.RepeatBehavior = RepeatBehavior.Forever; 
     Storyboard.SetTargetName(animation, "rtTTransform"); 
     animation.AutoReverse = false; 
     Storyboard.SetTargetProperty(animation, new PropertyPath(TranslateTransform.XProperty)); 

     storyboard.Children.Add(animation); 
     storyboard.Begin(marqueeText); 
    } 

在视图,控制被声明为

 <Canvas Grid.Column="1" HorizontalAlignment="Stretch" ClipToBounds="True" Margin="10,0"> 
      <TextBlock Canvas.Left="0" Canvas.Top="0" x:Name="marqueeText" TextWrapping="NoWrap" VerticalAlignment="Center" 
        Grid.Column="1" Foreground="{x:Static Brushes.White}" ClipToBounds="False" FontSize="16"> 
       <TextBlock.RenderTransform> 
        <TransformGroup> 
         <ScaleTransform ScaleX="1" ScaleY="1"/> 
         <SkewTransform AngleX="0" AngleY="0"/> 
         <RotateTransform Angle="0"/> 
         <TranslateTransform x:Name="rtTTransform"/> 
        </TransformGroup> 
       </TextBlock.RenderTransform> 
      </TextBlock> 
     </Canvas> 

在此先感谢我还在就这一个,并将与我找到的任何更改更新。

[已编辑]删除了AutoReverse,使事情变得更加困惑,并且更倾向于我试图完成的事情。

回答

2

我最终解决了这个问题,创建了一个在后台运行的线程,每隔一段时间更新一次文本,当文本结束滚动时,拉动任何最新的文本。

完整的例子是包含的,以防将来帮助其他人。

public Thread Updater; 
    public MyControl() 
    { 
     InitializeComponent(); 
     Loaded += OnLoad; 
     Updater = new Thread(ExecuteMarqueeUpdate); 
     Updater.Name = "MARQUEEUPDATE"; 
     Updater.IsBackground = true; 

     UpdateMarqueeInfo(); 
     marqueeText.Text = currentMarqueeText; 
     StartMarquee(); 
    } 
    public void ExecuteMarqueeUpdate() 
    { 
     while (true) 
     { 
      UpdateMarqueeInfo(); 
      Thread.Sleep(60000); 
     } 


    private string currentMarqueeText; 

    public void UpdateMarqueeInfo() 
    { 
     Random r = new Random(); 
     int i = r.Next(5, 8); 
     string s = ""; 
     for(int x = 0; x < i; x++) 
     { 
      s += "Is it possible to create a marquee or scrolling text in WPF? "; 
     } 
     currentMarqueeText = s; 
    } 

    public void StartMarquee() 
    { 
     var canvas = (Canvas)marqueeText.Parent; 
     if (marqueeText.ActualWidth < canvas.ActualWidth) return; 
     var duration = new Duration(TimeSpan.FromSeconds(marqueeText.ActualWidth/60)); 
     var animation = new DoubleAnimation(canvas.ActualWidth, -marqueeText.ActualWidth, duration); 
     Storyboard.SetTargetName(animation, "rtTTransform"); 
     Storyboard.SetTargetProperty(animation, new PropertyPath(TranslateTransform.XProperty)); 
     animation.Completed += OnMarqueeScrollComplete; 

     storyboard.Children.Clear(); 
     storyboard.Children.Add(animation); 
     storyboard.Begin(marqueeText); 
    } 

    private void OnMarqueeScrollComplete(object sender, EventArgs e) 
    { 
     if (!Updater.IsAlive) 
     { 
      Updater.Start(); 
     } 

     // Stop the running animation then reset the text. 
     // The data updates via the background thread, so just pull as available. 
     storyboard.Stop(); 
     marqueeText.Text = currentMarqueeText; 

     // Restart the marquee animation. 
     StartMarquee(); 
    } 
0

不太了解故事板动画,但我可以帮助“调用线程无法访问此对象”。

您的问题是计时器事件在计时器线程中触发,并且为了更新UI,您必须在UI线程中运行。解决这个问题的最简单方法是使用DispatcherTimer