All the controls missing in WPF. Over 1 million downloads.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

192 lines
8.2 KiB

// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Windows;
using System.Windows.Media.Animation;
namespace System.Windows.Controls.DataVisualization
{
/// <summary>
/// Represents a control that can animate the transitions between its specified
/// dependency property.
/// </summary>
internal static class DependencyPropertyAnimationHelper
{
/// <summary>
/// Number of key frames per second to generate the date time animations.
/// </summary>
public const int KeyFramesPerSecond = 20;
/// <summary>
/// The pattern used to ensure unique keys for the storyboards stored in
/// a framework element's resource dictionary.
/// </summary>
private const string StoryboardKeyPattern = "__{0}__";
/// <summary>
/// Returns a unique key for a storyboard.
/// </summary>
/// <param name="propertyPath">The property path of the property that
/// the storyboard animates.</param>
/// <returns>A unique key for a storyboard.</returns>
private static string GetStoryboardKey(string propertyPath)
{
return string.Format(CultureInfo.InvariantCulture, StoryboardKeyPattern, propertyPath);
}
/// <summary>
/// Starts animating a dependency property of a framework element to a
/// target value.
/// </summary>
/// <param name="target">The element to animate.</param>
/// <param name="animatingDependencyProperty">The dependency property to
/// animate.</param>
/// <param name="propertyPath">The path of the dependency property to
/// animate.</param>
/// <param name="targetValue">The value to animate the dependency
/// property to.</param>
/// <param name="timeSpan">The duration of the animation.</param>
/// <param name="easingFunction">The easing function to uses to
/// transition the data points.</param>
public static void BeginAnimation(
this FrameworkElement target,
DependencyProperty animatingDependencyProperty,
string propertyPath,
object targetValue,
TimeSpan timeSpan,
IEasingFunction easingFunction)
{
Storyboard storyBoard = target.Resources[GetStoryboardKey(propertyPath)] as Storyboard;
if (storyBoard != null)
{
#if SILVERLIGHT
// Save current value
object currentValue = target.GetValue(animatingDependencyProperty);
#endif
storyBoard.Stop();
#if SILVERLIGHT
// Restore that value so it doesn't snap back to its starting value
target.SetValue(animatingDependencyProperty, currentValue);
#endif
target.Resources.Remove(GetStoryboardKey(propertyPath));
}
storyBoard = CreateStoryboard(target, animatingDependencyProperty, propertyPath, ref targetValue, timeSpan, easingFunction);
storyBoard.Completed +=
(source, args) =>
{
storyBoard.Stop();
target.SetValue(animatingDependencyProperty, targetValue);
target.Resources.Remove(GetStoryboardKey(propertyPath));
};
target.Resources.Add(GetStoryboardKey(propertyPath), storyBoard);
storyBoard.Begin();
}
/// <summary>
/// Creates a story board that animates a dependency property to a
/// value.
/// </summary>
/// <param name="target">The element that is the target of the
/// storyboard.</param>
/// <param name="animatingDependencyProperty">The dependency property
/// to animate.</param>
/// <param name="propertyPath">The property path of the dependency
/// property to animate.</param>
/// <param name="toValue">The value to animate the dependency property
/// to.</param>
/// <param name="durationTimeSpan">The duration of the animation.
/// </param>
/// <param name="easingFunction">The easing function to use to
/// transition the data points.</param>
/// <returns>The story board that animates the property.</returns>
[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "easingFunction", Justification = "This parameter is used in Silverlight.")]
private static Storyboard CreateStoryboard(
FrameworkElement target,
DependencyProperty animatingDependencyProperty,
string propertyPath,
ref object toValue,
TimeSpan durationTimeSpan,
IEasingFunction easingFunction)
{
object fromValue = target.GetValue(animatingDependencyProperty);
double fromDoubleValue;
double toDoubleValue;
DateTime fromDateTime;
DateTime toDateTime;
Storyboard storyBoard = new Storyboard();
Storyboard.SetTarget(storyBoard, target);
Storyboard.SetTargetProperty(storyBoard, new PropertyPath(propertyPath));
if ((fromValue != null && toValue != null))
{
if (ValueHelper.TryConvert(fromValue, out fromDoubleValue) && ValueHelper.TryConvert(toValue, out toDoubleValue))
{
DoubleAnimation doubleAnimation = new DoubleAnimation();
#if !NO_EASING_FUNCTIONS
doubleAnimation.EasingFunction = easingFunction;
#endif
doubleAnimation.Duration = durationTimeSpan;
doubleAnimation.To = ValueHelper.ToDouble(toValue);
toValue = doubleAnimation.To;
storyBoard.Children.Add(doubleAnimation);
}
else if (ValueHelper.TryConvert(fromValue, out fromDateTime) && ValueHelper.TryConvert(toValue, out toDateTime))
{
ObjectAnimationUsingKeyFrames keyFrameAnimation = new ObjectAnimationUsingKeyFrames();
keyFrameAnimation.Duration = durationTimeSpan;
long intervals = (long)(durationTimeSpan.TotalSeconds * KeyFramesPerSecond);
if (intervals < 2L)
{
intervals = 2L;
}
IEnumerable<TimeSpan> timeSpanIntervals =
ValueHelper.GetTimeSpanIntervalsInclusive(durationTimeSpan, intervals);
IEnumerable<DateTime> dateTimeIntervals =
ValueHelper.GetDateTimesBetweenInclusive(fromDateTime, toDateTime, intervals);
IEnumerable<DiscreteObjectKeyFrame> keyFrames =
EnumerableFunctions.Zip(
dateTimeIntervals,
timeSpanIntervals,
(dateTime, timeSpan) => new DiscreteObjectKeyFrame() { Value = dateTime, KeyTime = timeSpan });
foreach (DiscreteObjectKeyFrame keyFrame in keyFrames)
{
keyFrameAnimation.KeyFrames.Add(keyFrame);
toValue = keyFrame.Value;
}
storyBoard.Children.Add(keyFrameAnimation);
}
}
if (storyBoard.Children.Count == 0)
{
ObjectAnimationUsingKeyFrames keyFrameAnimation = new ObjectAnimationUsingKeyFrames();
DiscreteObjectKeyFrame endFrame = new DiscreteObjectKeyFrame() { Value = toValue, KeyTime = new TimeSpan(0, 0, 0) };
keyFrameAnimation.KeyFrames.Add(endFrame);
storyBoard.Children.Add(keyFrameAnimation);
}
return storyBoard;
}
}
}