Files
TickerLib/Animation/Ticker.cs
2024-02-23 06:55:00 -05:00

95 lines
3.5 KiB
C#

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