2009-04-22 75 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