private void animScroll_Completed(object sender, EventArgs e) { Clock clock = (Clock)sender; TaggedDoubleAnimation ani = (TaggedDoubleAnimation)clock.Timeline; FrameworkElement element = ani.TargetElement; tickerContainer.Children.Remove(element); }
//displayNext will first retrieve the next TickerItemElement //to be displayed, and then move the listPointer listPoint up by //1. Then the function animItem is called on the retrieved element //The retrieved item is added as a child of the tickers //container. //However, if the pointer variable listPoint exceeds the length //of the list of items, it will then execute the same actions as //in the Refresh function. The Refresh function itself cannot be //called as the if statement will not pass the required parameters. private void animItem(FrameworkElement e) { //animItem acts on a FrameWorkElement e e.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity)); e.Arrange(new Rect(e.DesiredSize)); //The element is scaled and arranged in the standard method, into //a rectangle of suitable size startPos = tickerContainer.ActualWidth; endPos = -1000; //The start position is the far right of the ticker, and the end position is //1000 pixels off of the far left of the ticker, so that items can be removed //invisibly. This value is large since items with long descriptions, particularly //at larger font sizes, may still have the description showing when they are //removed otherwise unitsPerSec = Convert.ToInt32((Math.Abs(startPos - endPos)) / (animDuration.TotalSeconds)); nextFire = Convert.ToInt32((e.ActualWidth + seperatorSize) / unitsPerSec); //To calculate the appropriate time interval between a new item being //scrolled along the screen, the amount of units per second is first //defined as the full animation width, over the specified duration //value in seconds. Then, using the width of the TickerItemElement //and a seperator to prevent overlap, we calculate nextFire as this //width plus the seperator size, divided by the units per second value //This thusly defines the appropriate interval, which is recalculated //each time to ensure that animation continues as expected. This //nextFire variable specifies when the next item of news is to be scrolled //along the screen, providing separation between newsitems so there is //no overlap. animTimer.Stop(); animTimer.Interval = new TimeSpan(0, 0, nextFire); animTimer.Start(); //animTimer is stopped and restarted, with the new interval //nextFire. As nextFire is calculated as a seconds value, //this is placed in the seconds part of the new TimeSpan object. animScroll = new TaggedDoubleAnimation(); animScroll.From = startPos; animScroll.To = endPos; animScroll.TargetElement = e; animScroll.Duration = new Duration(animDuration); animScroll.Completed += animScroll_Completed; //animScroll is defined as a newTaggedDoubleAnimation, which animates from startPos //to endPos, targeted on the TickerItemElement e. Its duration is formulated from //the animDuration value, which is affected by the user set percentage modifier //of the original speed value. translate = new TranslateTransform(); e.RenderTransform = translate; //A new TranslateTransform object is created, and this object is associated with the //RenderTransform dependency property of the news item to be scrolled translate.BeginAnimation(TranslateTransform.XProperty, animScroll, HandoffBehavior.Compose); //Then, the animation is began, translating the X property of the TickerItemElement, the //animScroll animation used to animate this property, and the handoff behavior is set to //compose }