using System; using System.Collections.Generic; using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Threading; namespace Ticker.Animation { public class Ticker where T : FrameworkElement { private static int DISPLAY_TIMER_SPEED_SECONDS=40; // This is the speed used to traverse the display from right to left private static int DISPLAY_TIMER_INTERVAL_MILLISECONDS=1000; // This is the interval of time between displaying successive items private readonly DispatcherTimer displayTimer=new DispatcherTimer(DispatcherPriority.Normal); // new DispatcherTimer(); public EventHandler> ItemDisplayed; public Ticker(Panel container) { SeperatorSize = 25; Container = container; Container.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity)); Container.Arrange(new Rect(Container.DesiredSize)); Speed = new TimeSpan(0, 0, 0, DISPLAY_TIMER_SPEED_SECONDS); Items = new Queue(); displayTimer.Tick += displayTimer_Tick; displayTimer.Start(); IsRunning = true; } public virtual void Dispose() { Stop(); } public bool IsRunning { get; set; } public void Stop() { if(!IsRunning)return; if(null!=displayTimer)displayTimer.Stop(); IsRunning = false; } public void Start() { if(IsRunning)return; if(null==displayTimer)return; displayTimer.Start(); displayTimer.Interval = new TimeSpan(0,0,0,0,DISPLAY_TIMER_INTERVAL_MILLISECONDS); IsRunning = true; } public double SeperatorSize { get; set; } public TimeSpan Speed { get; set; } public Queue Items { get; set; } public Panel Container { get; private set; } private void displayTimer_Tick(object sender, EventArgs e) { DisplayNextItem(); } private void DisplayNextItem() { if (Items.Count == 0)return; T item = Items.Dequeue(); Container.Children.Add(item); AnimateMove(item); if (ItemDisplayed != null) ItemDisplayed(this, new ItemEventArgs(item)); } private void AnimateMove(FrameworkElement e) { e.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity)); e.Arrange(new Rect(e.DesiredSize)); double from = Container.ActualWidth; double to = -500; int unitsPerSec = Convert.ToInt32(Math.Abs(from - to)/Speed.TotalSeconds); int nextFire = Convert.ToInt32((e.ActualWidth + SeperatorSize)/unitsPerSec); displayTimer.Stop(); displayTimer.Interval = new TimeSpan(0, 0, nextFire); // displayTimer.Dispatcher.Thread.Priority=ThreadPriority.AboveNormal; displayTimer.Start(); TaggedDoubleAnimation animation = new TaggedDoubleAnimation(); animation.From = from; animation.To = to; animation.Duration = new Duration(Speed); animation.TargetElement = e; animation.Completed += ani_Completed; TranslateTransform translateTransform = new TranslateTransform(); e.RenderTransform = translateTransform; translateTransform.BeginAnimation(TranslateTransform.XProperty, animation, HandoffBehavior.Compose); } private void ani_Completed(object sender, EventArgs e) { Clock clock = (Clock) sender; TaggedDoubleAnimation animation = (TaggedDoubleAnimation) clock.Timeline; FrameworkElement element = animation.TargetElement; Container.Children.Remove(element); } } }