【问题标题】:Scrolling text update problems滚动文本更新问题
【发布时间】:2009-04-22 16:47:39
【问题描述】:

我有一些从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,让事情变得不那么混乱,更接近我想要完成的目标。

【问题讨论】:

    标签: c# wpf xaml animation


    【解决方案1】:

    我最终通过创建一个在后台运行的线程来解决问题,该线程每隔一段时间更新文本,当文本完成滚动时,拉出最新的文本。

    包含完整示例,以防将来对其他人有所帮助。

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-04
        • 1970-01-01
        • 2017-08-05
        相关资源
        最近更新 更多