






using System;using System.Collections.Generic;using System.Windows;using System.Windows.Controls;using System.Windows.Media.Animation;namespace WPFSpark{  /// <summary>  /// Interaction logic for FluidProgressBar.xaml  /// </summary>  public partial class FluidProgressBar : UserControl, IDisposable  {    #region Internal class    private class KeyFrameDetails    {      public KeyTime KeyFrameTime { get; set; }      public List<DoubleKeyFrame> KeyFrames { get; set; }    }    #endregion    #region Fields    Dictionary<int, KeyFrameDetails> keyFrameMap = null;    Dictionary<int, KeyFrameDetails> opKeyFrameMap = null;    //KeyTime keyA = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(0));    //KeyTime keyB = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(0.5));    //KeyTime keyC = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(2.0));    //KeyTime keyD = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(2.5));    Storyboard sb;    bool isStoryboardRunning;    #endregion    #region Dependency Properties    #region Delay    /// <summary>    /// Delay Dependency Property    /// </summary>    public static readonly DependencyProperty DelayProperty =      DependencyProperty.Register("Delay", typeof(Duration), typeof(FluidProgressBar),        new FrameworkPropertyMetadata(new Duration(TimeSpan.FromMilliseconds(100)), new PropertyChangedCallback(OnDelayChanged)));    /// <summary>    /// Gets or sets the Delay property. This dependency property     /// indicates the delay between adjacent animation timelines.    /// </summary>    public Duration Delay    {      get { return (Duration)GetValue(DelayProperty); }      set { SetValue(DelayProperty, value); }    }    /// <summary>    /// Handles changes to the Delay property.    /// </summary>    /// <param name="d">FluidProgressBar</param>    /// <param name="e">DependencyProperty changed event arguments</param>    private static void OnDelayChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)    {      FluidProgressBar pBar = (FluidProgressBar)d;      Duration oldDelay = (Duration)e.OldValue;      Duration newDelay = pBar.Delay;      pBar.OnDelayChanged(oldDelay, newDelay);    }    /// <summary>    /// Provides derived classes an opportunity to handle changes to the Delay property.    /// </summary>    /// <param name="oldDelay">Old Value</param>    /// <param name="newDelay">New Value</param>    protected virtual void OnDelayChanged(Duration oldDelay, Duration newDelay)    {      bool isActive = isStoryboardRunning;      if (isActive)        StopFluidAnimation();      UpdateTimelineDelay(newDelay);      if (isActive)        StartFluidAnimation();    }    #endregion    #region DotWidth    /// <summary>    /// DotWidth Dependency Property    /// </summary>    public static readonly DependencyProperty DotWidthProperty =      DependencyProperty.Register("DotWidth", typeof(double), typeof(FluidProgressBar),        new FrameworkPropertyMetadata(4.0, new PropertyChangedCallback(OnDotWidthChanged)));    /// <summary>    /// Gets or sets the DotWidth property. This dependency property     /// indicates the width of each of the dots.    /// </summary>    public double DotWidth    {      get { return (double)GetValue(DotWidthProperty); }      set { SetValue(DotWidthProperty, value); }    }    /// <summary>    /// Handles changes to the DotWidth property.    /// </summary>    /// <param name="d">FluidProgressBar</param>    /// <param name="e">DependencyProperty changed event arguments</param>    private static void OnDotWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)    {      FluidProgressBar pBar = (FluidProgressBar)d;      double oldDotWidth = (double)e.OldValue;      double newDotWidth = pBar.DotWidth;      pBar.OnDotWidthChanged(oldDotWidth, newDotWidth);    }    /// <summary>    /// Provides derived classes an opportunity to handle changes to the DotWidth property.    /// </summary>    /// <param name="oldDotWidth">Old Value</param>    /// <param name="newDotWidth">New Value</param>    protected virtual void OnDotWidthChanged(double oldDotWidth, double newDotWidth)    {      if (isStoryboardRunning)        RestartStoryboardAnimation();    }    #endregion    #region DotHeight    /// <summary>    /// DotHeight Dependency Property    /// </summary>    public static readonly DependencyProperty DotHeightProperty =      DependencyProperty.Register("DotHeight", typeof(double), typeof(FluidProgressBar),        new FrameworkPropertyMetadata(4.0, new PropertyChangedCallback(OnDotHeightChanged)));    /// <summary>    /// Gets or sets the DotHeight property. This dependency property     /// indicates the height of each of the dots.    /// </summary>    public double DotHeight    {      get { return (double)GetValue(DotHeightProperty); }      set { SetValue(DotHeightProperty, value); }    }    /// <summary>    /// Handles changes to the DotHeight property.    /// </summary>    /// <param name="d">FluidProgressBar</param>    /// <param name="e">DependencyProperty changed event arguments</param>    private static void OnDotHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)    {      FluidProgressBar pBar = (FluidProgressBar)d;      double oldDotHeight = (double)e.OldValue;      double newDotHeight = pBar.DotHeight;      pBar.OnDotHeightChanged(oldDotHeight, newDotHeight);    }    /// <summary>    /// Provides derived classes an opportunity to handle changes to the DotHeight property.    /// </summary>    /// <param name="oldDotHeight">Old Value</param>    /// <param name="newDotHeight">New Value</param>    protected virtual void OnDotHeightChanged(double oldDotHeight, double newDotHeight)    {      if (isStoryboardRunning)        RestartStoryboardAnimation();    }    #endregion    #region DotRadiusX    /// <summary>    /// DotRadiusX Dependency Property    /// </summary>    public static readonly DependencyProperty DotRadiusXProperty =      DependencyProperty.Register("DotRadiusX", typeof(double), typeof(FluidProgressBar),        new FrameworkPropertyMetadata(0.0, new PropertyChangedCallback(OnDotRadiusXChanged)));    /// <summary>    /// Gets or sets the DotRadiusX property. This dependency property     /// indicates the corner radius width of each of the dot.    /// </summary>    public double DotRadiusX    {      get { return (double)GetValue(DotRadiusXProperty); }      set { SetValue(DotRadiusXProperty, value); }    }    /// <summary>    /// Handles changes to the DotRadiusX property.    /// </summary>    /// <param name="d">FluidProgressBar</param>    /// <param name="e">DependencyProperty changed event arguments</param>    private static void OnDotRadiusXChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)    {      FluidProgressBar pBar = (FluidProgressBar)d;      double oldDotRadiusX = (double)e.OldValue;      double newDotRadiusX = pBar.DotRadiusX;      pBar.OnDotRadiusXChanged(oldDotRadiusX, newDotRadiusX);    }    /// <summary>    /// Provides derived classes an opportunity to handle changes to the DotRadiusX property.    /// </summary>    /// <param name="oldDotRadiusX">Old Value</param>    /// <param name="newDotRadiusX">New Value</param>    protected virtual void OnDotRadiusXChanged(double oldDotRadiusX, double newDotRadiusX)    {      if (isStoryboardRunning)        RestartStoryboardAnimation();    }    #endregion    #region DotRadiusY    /// <summary>    /// DotRadiusY Dependency Property    /// </summary>    public static readonly DependencyProperty DotRadiusYProperty =      DependencyProperty.Register("DotRadiusY", typeof(double), typeof(FluidProgressBar),        new FrameworkPropertyMetadata(0.0, new PropertyChangedCallback(OnDotRadiusYChanged)));    /// <summary>    /// Gets or sets the DotRadiusY property. This dependency property     /// indicates the corner height of each of the dots.    /// </summary>    public double DotRadiusY    {      get { return (double)GetValue(DotRadiusYProperty); }      set { SetValue(DotRadiusYProperty, value); }    }    /// <summary>    /// Handles changes to the DotRadiusY property.    /// </summary>    /// <param name="d">FluidProgressBar</param>    /// <param name="e">DependencyProperty changed event arguments</param>    private static void OnDotRadiusYChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)    {      FluidProgressBar pBar = (FluidProgressBar)d;      double oldDotRadiusY = (double)e.OldValue;      double newDotRadiusY = pBar.DotRadiusY;      pBar.OnDotRadiusYChanged(oldDotRadiusY, newDotRadiusY);    }    /// <summary>    /// Provides derived classes an opportunity to handle changes to the DotRadiusY property.    /// </summary>    /// <param name="oldDotRadiusY">Old Value</param>    /// <param name="newDotRadiusY">New Value</param>    protected virtual void OnDotRadiusYChanged(double oldDotRadiusY, double newDotRadiusY)    {      if (isStoryboardRunning)        RestartStoryboardAnimation();    }    #endregion    #region DurationA    /// <summary>    /// DurationA Dependency Property    /// </summary>    public static readonly DependencyProperty DurationAProperty =      DependencyProperty.Register("DurationA", typeof(Duration), typeof(FluidProgressBar),        new FrameworkPropertyMetadata(new Duration(TimeSpan.FromSeconds(0.5)), new PropertyChangedCallback(OnDurationAChanged)));    /// <summary>    /// Gets or sets the DurationA property. This dependency property     /// indicates the duration of the animation from the start point till KeyFrameA.    /// </summary>    public Duration DurationA    {      get { return (Duration)GetValue(DurationAProperty); }      set { SetValue(DurationAProperty, value); }    }    /// <summary>    /// Handles changes to the DurationA property.    /// </summary>    /// <param name="d">FluidProgressBar</param>    /// <param name="e">DependencyProperty changed event arguments</param>    private static void OnDurationAChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)    {      FluidProgressBar pBar = (FluidProgressBar)d;      Duration oldDurationA = (Duration)e.OldValue;      Duration newDurationA = pBar.DurationA;      pBar.OnDurationAChanged(oldDurationA, newDurationA);    }    /// <summary>    /// Provides derived classes an opportunity to handle changes to the DurationA property.    /// </summary>    /// <param name="oldDurationA">Old Value</param>    /// <param name="newDurationA">New Value</param>    protected virtual void OnDurationAChanged(Duration oldDurationA, Duration newDurationA)    {      bool isActive = isStoryboardRunning;      if (isActive)        StopFluidAnimation();      UpdateKeyTimes(1, newDurationA);      if (isActive)        StartFluidAnimation();    }    #endregion    #region DurationB    /// <summary>    /// DurationB Dependency Property    /// </summary>    public static readonly DependencyProperty DurationBProperty =      DependencyProperty.Register("DurationB", typeof(Duration), typeof(FluidProgressBar),        new FrameworkPropertyMetadata(new Duration(TimeSpan.FromSeconds(1.5)), new PropertyChangedCallback(OnDurationBChanged)));    /// <summary>    /// Gets or sets the DurationB property. This dependency property     /// indicates the duration of the animation from the KeyFrameA till KeyFrameB.    /// </summary>    public Duration DurationB    {      get { return (Duration)GetValue(DurationBProperty); }      set { SetValue(DurationBProperty, value); }    }    /// <summary>    /// Handles changes to the DurationB property.    /// </summary>    /// <param name="d">FluidProgressBar</param>    /// <param name="e">DependencyProperty changed event arguments</param>    private static void OnDurationBChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)    {      FluidProgressBar pBar = (FluidProgressBar)d;      Duration oldDurationB = (Duration)e.OldValue;      Duration newDurationB = pBar.DurationB;      pBar.OnDurationBChanged(oldDurationB, newDurationB);    }    /// <summary>    /// Provides derived classes an opportunity to handle changes to the DurationB property.    /// </summary>    /// <param name="oldDurationB">Old Value</param>    /// <param name="newDurationB">New Value</param>    protected virtual void OnDurationBChanged(Duration oldDurationB, Duration newDurationB)    {      bool isActive = isStoryboardRunning;      if (isActive)        StopFluidAnimation();      UpdateKeyTimes(2, newDurationB);      if (isActive)        StartFluidAnimation();    }    #endregion    #region DurationC    /// <summary>    /// DurationC Dependency Property    /// </summary>    public static readonly DependencyProperty DurationCProperty =      DependencyProperty.Register("DurationC", typeof(Duration), typeof(FluidProgressBar),        new FrameworkPropertyMetadata(new Duration(TimeSpan.FromSeconds(0.5)), new PropertyChangedCallback(OnDurationCChanged)));    /// <summary>    /// Gets or sets the DurationC property. This dependency property     /// indicates the duration of the animation from KeyFrameB till the end point.    /// </summary>    public Duration DurationC    {      get { return (Duration)GetValue(DurationCProperty); }      set { SetValue(DurationCProperty, value); }    }    /// <summary>    /// Handles changes to the DurationC property.    /// </summary>    /// <param name="d">FluidProgressBar</param>    /// <param name="e">DependencyProperty changed event arguments</param>    private static void OnDurationCChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)    {      FluidProgressBar pBar = (FluidProgressBar)d;      Duration oldDurationC = (Duration)e.OldValue;      Duration newDurationC = pBar.DurationC;      pBar.OnDurationCChanged(oldDurationC, newDurationC);    }    /// <summary>    /// Provides derived classes an opportunity to handle changes to the DurationC property.    /// </summary>    /// <param name="oldDurationC">Old Value</param>    /// <param name="newDurationC">New Value</param>    protected virtual void OnDurationCChanged(Duration oldDurationC, Duration newDurationC)    {      bool isActive = isStoryboardRunning;      if (isActive)        StopFluidAnimation();      UpdateKeyTimes(3, newDurationC);      if (isActive)        StartFluidAnimation();    }    #endregion    #region KeyFrameA    /// <summary>    /// KeyFrameA Dependency Property    /// </summary>    public static readonly DependencyProperty KeyFrameAProperty =      DependencyProperty.Register("KeyFrameA", typeof(double), typeof(FluidProgressBar),        new FrameworkPropertyMetadata(0.33, new PropertyChangedCallback(OnKeyFrameAChanged)));    /// <summary>    /// Gets or sets the KeyFrameA property. This dependency property     /// indicates the first KeyFrame position after the initial keyframe.    /// </summary>    public double KeyFrameA    {      get { return (double)GetValue(KeyFrameAProperty); }      set { SetValue(KeyFrameAProperty, value); }    }    /// <summary>    /// Handles changes to the KeyFrameA property.    /// </summary>    /// <param name="d">FluidProgressBar</param>    /// <param name="e">DependencyProperty changed event arguments</param>    private static void OnKeyFrameAChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)    {      FluidProgressBar pBar = (FluidProgressBar)d;      double oldKeyFrameA = (double)e.OldValue;      double newKeyFrameA = pBar.KeyFrameA;      pBar.OnKeyFrameAChanged(oldKeyFrameA, newKeyFrameA);    }    /// <summary>    /// Provides derived classes an opportunity to handle changes to the KeyFrameA property.    /// </summary>    /// <param name="oldKeyFrameA">Old Value</param>    /// <param name="newKeyFrameA">New Value</param>    protected virtual void OnKeyFrameAChanged(double oldKeyFrameA, double newKeyFrameA)    {      RestartStoryboardAnimation();    }    #endregion    #region KeyFrameB    /// <summary>    /// KeyFrameB Dependency Property    /// </summary>    public static readonly DependencyProperty KeyFrameBProperty =      DependencyProperty.Register("KeyFrameB", typeof(double), typeof(FluidProgressBar),        new FrameworkPropertyMetadata(0.63, new PropertyChangedCallback(OnKeyFrameBChanged)));    /// <summary>    /// Gets or sets the KeyFrameB property. This dependency property     /// indicates the second KeyFrame position after the initial keyframe.    /// </summary>    public double KeyFrameB    {      get { return (double)GetValue(KeyFrameBProperty); }      set { SetValue(KeyFrameBProperty, value); }    }    /// <summary>    /// Handles changes to the KeyFrameB property.    /// </summary>    /// <param name="d">FluidProgressBar</param>    /// <param name="e">DependencyProperty changed event arguments</param>    private static void OnKeyFrameBChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)    {      FluidProgressBar pBar = (FluidProgressBar)d;      double oldKeyFrameB = (double)e.OldValue;      double newKeyFrameB = pBar.KeyFrameB;      pBar.OnKeyFrameBChanged(oldKeyFrameB, newKeyFrameB);    }    /// <summary>    /// Provides derived classes an opportunity to handle changes to the KeyFrameB property.    /// </summary>    /// <param name="oldKeyFrameB">Old Value</param>    /// <param name="newKeyFrameB">New Value</param>    protected virtual void OnKeyFrameBChanged(double oldKeyFrameB, double newKeyFrameB)    {      RestartStoryboardAnimation();    }    #endregion    #region Oscillate    /// <summary>    /// Oscillate Dependency Property    /// </summary>    public static readonly DependencyProperty OscillateProperty =      DependencyProperty.Register("Oscillate", typeof(bool), typeof(FluidProgressBar),        new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnOscillateChanged)));    /// <summary>    /// Gets or sets the Oscillate property. This dependency property     /// indicates whether the animation should oscillate.    /// </summary>    public bool Oscillate    {      get { return (bool)GetValue(OscillateProperty); }      set { SetValue(OscillateProperty, value); }    }    /// <summary>    /// Handles changes to the Oscillate property.    /// </summary>    /// <param name="d">FluidProgressBar</param>    /// <param name="e">DependencyProperty changed event arguments</param>    private static void OnOscillateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)    {      FluidProgressBar pBar = (FluidProgressBar)d;      bool oldOscillate = (bool)e.OldValue;      bool newOscillate = pBar.Oscillate;      pBar.OnOscillateChanged(oldOscillate, newOscillate);    }    /// <summary>    /// Provides derived classes an opportunity to handle changes to the Oscillate property.    /// </summary>    /// <param name="oldOscillate">Old Value</param>    /// <param name="newOscillate">New Value</param>    protected virtual void OnOscillateChanged(bool oldOscillate, bool newOscillate)    {      if (sb != null)      {        StopFluidAnimation();        sb.AutoReverse = newOscillate;        sb.Duration = newOscillate ? ReverseDuration : TotalDuration;        StartFluidAnimation();      }    }    #endregion    #region ReverseDuration    /// <summary>    /// ReverseDuration Dependency Property    /// </summary>    public static readonly DependencyProperty ReverseDurationProperty =      DependencyProperty.Register("ReverseDuration", typeof(Duration), typeof(FluidProgressBar),        new FrameworkPropertyMetadata(new Duration(TimeSpan.FromSeconds(2.9)), new PropertyChangedCallback(OnReverseDurationChanged)));    /// <summary>    /// Gets or sets the ReverseDuration property. This dependency property     /// indicates the duration of the total animation in reverse.    /// </summary>    public Duration ReverseDuration    {      get { return (Duration)GetValue(ReverseDurationProperty); }      set { SetValue(ReverseDurationProperty, value); }    }    /// <summary>    /// Handles changes to the ReverseDuration property.    /// </summary>    /// <param name="d">FluidProgressBar</param>    /// <param name="e">DependencyProperty changed event arguments</param>    private static void OnReverseDurationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)    {      FluidProgressBar pBar = (FluidProgressBar)d;      Duration oldReverseDuration = (Duration)e.OldValue;      Duration newReverseDuration = pBar.ReverseDuration;      pBar.OnReverseDurationChanged(oldReverseDuration, newReverseDuration);    }    /// <summary>    /// Provides derived classes an opportunity to handle changes to the ReverseDuration property.    /// </summary>    /// <param name="oldReverseDuration">Old Value</param>    /// <param name="newReverseDuration">New Value</param>    protected virtual void OnReverseDurationChanged(Duration oldReverseDuration, Duration newReverseDuration)    {      if ((sb != null) && (Oscillate))      {        sb.Duration = newReverseDuration;        RestartStoryboardAnimation();      }    }    #endregion    #region TotalDuration    /// <summary>    /// TotalDuration Dependency Property    /// </summary>    public static readonly DependencyProperty TotalDurationProperty =      DependencyProperty.Register("TotalDuration", typeof(Duration), typeof(FluidProgressBar),        new FrameworkPropertyMetadata(new Duration(TimeSpan.FromSeconds(4.4)), new PropertyChangedCallback(OnTotalDurationChanged)));    /// <summary>    /// Gets or sets the TotalDuration property. This dependency property     /// indicates the duration of the complete animation.    /// </summary>    public Duration TotalDuration    {      get { return (Duration)GetValue(TotalDurationProperty); }      set { SetValue(TotalDurationProperty, value); }    }    /// <summary>    /// Handles changes to the TotalDuration property.    /// </summary>    /// <param name="d">FluidProgressBar</param>    /// <param name="e">DependencyProperty changed event arguments</param>    private static void OnTotalDurationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)    {      FluidProgressBar pBar = (FluidProgressBar)d;      Duration oldTotalDuration = (Duration)e.OldValue;      Duration newTotalDuration = pBar.TotalDuration;      pBar.OnTotalDurationChanged(oldTotalDuration, newTotalDuration);    }    /// <summary>    /// Provides derived classes an opportunity to handle changes to the TotalDuration property.    /// </summary>    /// <param name="oldTotalDuration">Old Value</param>    /// <param name="newTotalDuration">New Value</param>    protected virtual void OnTotalDurationChanged(Duration oldTotalDuration, Duration newTotalDuration)    {      if ((sb != null) && (!Oscillate))      {        sb.Duration = newTotalDuration;        RestartStoryboardAnimation();      }    }    #endregion    #endregion    #region Construction / Initialization    /// <summary>    /// Ctor    /// </summary>    public FluidProgressBar()    {      InitializeComponent();      keyFrameMap = new Dictionary<int, KeyFrameDetails>();      opKeyFrameMap = new Dictionary<int, KeyFrameDetails>();      GetKeyFramesFromStoryboard();      this.SizeChanged = new SizeChangedEventHandler(OnSizeChanged);      this.Loaded = new RoutedEventHandler(OnLoaded);      this.IsVisibleChanged = new DependencyPropertyChangedEventHandler(OnIsVisibleChanged);    }    #endregion    #region Event Handlers    /// <summary>    /// Handles the Loaded event    /// </summary>    /// <param name="sender">Sender</param>    /// <param name="e">EventArgs</param>    void OnLoaded(object sender, System.Windows.RoutedEventArgs e)    {      // Update the key frames      UpdateKeyFrames();      // Start the animation      StartFluidAnimation();    }    /// <summary>    /// Handles the SizeChanged event    /// </summary>    /// <param name="sender">Sender</param>    /// <param name="e">EventArgs</param>    void OnSizeChanged(object sender, System.Windows.SizeChangedEventArgs e)    {      // Restart the animation      RestartStoryboardAnimation();    }    /// <summary>    /// Handles the IsVisibleChanged event    /// </summary>    /// <param name="sender">Sender</param>    /// <param name="e">EventArgs</param>    void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)    {      if (this.Visibility == Visibility.Visible)      {        UpdateKeyFrames();        StartFluidAnimation();      }      else      {        StopFluidAnimation();      }    }    #endregion    #region Helpers    /// <summary>    /// Starts the animation    /// </summary>    private void StartFluidAnimation()    {      if ((sb != null) && (!isStoryboardRunning))      {        sb.Begin();        isStoryboardRunning = true;      }    }    /// <summary>    /// Stops the animation    /// </summary>    private void StopFluidAnimation()    {      if ((sb != null) && (isStoryboardRunning))      {        // Move the timeline to the end and stop the animation        sb.SeekAlignedToLastTick(TimeSpan.FromSeconds(0));        sb.Stop();        isStoryboardRunning = false;      }    }    /// <summary>    /// Stops the animation, updates the keyframes and starts the animation    /// </summary>    private void RestartStoryboardAnimation()    {      StopFluidAnimation();      UpdateKeyFrames();      StartFluidAnimation();    }    /// <summary>    /// Obtains the keyframes for each animation in the storyboard so that    /// they can be updated when required.    /// </summary>    private void GetKeyFramesFromStoryboard()    {      sb = (Storyboard)this.Resources["FluidStoryboard"];      if (sb != null)      {        foreach (Timeline timeline in sb.Children)        {          DoubleAnimationUsingKeyFrames dakeys = timeline as DoubleAnimationUsingKeyFrames;          if (dakeys != null)          {            string targetName = Storyboard.GetTargetName(dakeys);            ProcessDoubleAnimationWithKeys(dakeys, !targetName.StartsWith("Trans"));          }        }      }    }    /// <summary>    /// Gets the keyframes in the given animation and stores them in a map    /// </summary>    /// <param name="dakeys">Animation containg keyframes</param>    /// <param name="isOpacityAnim">Flag to indicate whether the animation targets the opacity or the translate transform</param>    private void ProcessDoubleAnimationWithKeys(DoubleAnimationUsingKeyFrames dakeys, bool isOpacityAnim = false)    {      // Get all the keyframes in the instance.      for (int i = 0; i < dakeys.KeyFrames.Count; i )      {        DoubleKeyFrame frame = dakeys.KeyFrames[i];        Dictionary<int, KeyFrameDetails> targetMap = null;        if (isOpacityAnim)        {          targetMap = opKeyFrameMap;        }        else        {          targetMap = keyFrameMap;        }        if (!targetMap.ContainsKey(i))        {          targetMap[i] = new KeyFrameDetails() { KeyFrames = new List<DoubleKeyFrame>() };        }        // Update the keyframe time and add it to the map        targetMap[i].KeyFrameTime = frame.KeyTime;        targetMap[i].KeyFrames.Add(frame);      }    }    /// <summary>    /// Update the key value of each keyframe based on the current width of the FluidProgressBar    /// </summary>    private void UpdateKeyFrames()    {      // Get the current width of the FluidProgressBar      double width = this.ActualWidth;      // Update the values only if the current width is greater than Zero and is visible      if ((width > 0.0) && (this.Visibility == System.Windows.Visibility.Visible))      {        double Point0 = -10;        double PointA = width * KeyFrameA;        double PointB = width * KeyFrameB;        double PointC = width  10;        // Update the keyframes stored in the map        UpdateKeyFrame(0, Point0);        UpdateKeyFrame(1, PointA);        UpdateKeyFrame(2, PointB);        UpdateKeyFrame(3, PointC);      }    }    /// <summary>    /// Update the key value of the keyframes stored in the map    /// </summary>    /// <param name="key">Key of the dictionary</param>    /// <param name="newValue">New value to be given to the key value of the keyframes</param>    private void UpdateKeyFrame(int key, double newValue)    {      if (keyFrameMap.ContainsKey(key))      {        foreach (var frame in keyFrameMap[key].KeyFrames)        {          if (frame is LinearDoubleKeyFrame)          {            frame.SetValue(LinearDoubleKeyFrame.ValueProperty, newValue);          }          else if (frame is EasingDoubleKeyFrame)          {            frame.SetValue(EasingDoubleKeyFrame.ValueProperty, newValue);          }        }      }    }    /// <summary>    /// Updates the duration of each of the keyframes stored in the map    /// </summary>    /// <param name="key">Key of the dictionary</param>    /// <param name="newValue">New value to be given to the duration value of the keyframes</param>    private void UpdateKeyTimes(int key, Duration newDuration)    {      switch (key)      {        case 1:          UpdateKeyTime(1, newDuration);          UpdateKeyTime(2, newDuration  DurationB);          UpdateKeyTime(3, newDuration  DurationB  DurationC);          break;        case 2:          UpdateKeyTime(2, DurationA  newDuration);          UpdateKeyTime(3, DurationA  newDuration  DurationC);          break;        case 3:          UpdateKeyTime(3, DurationA  DurationB  newDuration);          break;        default:          break;      }      // Update the opacity animation duration based on the complete duration      // of the animation      UpdateOpacityKeyTime(1, DurationA  DurationB  DurationC);    }    /// <summary>    /// Updates the duration of each of the keyframes stored in the map    /// </summary>    /// <param name="key">Key of the dictionary</param>    /// <param name="newDuration">New value to be given to the duration value of the keyframes</param>    private void UpdateKeyTime(int key, Duration newDuration)    {      if (keyFrameMap.ContainsKey(key))      {        KeyTime newKeyTime = KeyTime.FromTimeSpan(newDuration.TimeSpan);        keyFrameMap[key].KeyFrameTime = newKeyTime;        foreach (var frame in keyFrameMap[key].KeyFrames)        {          if (frame is LinearDoubleKeyFrame)          {            frame.SetValue(LinearDoubleKeyFrame.KeyTimeProperty, newKeyTime);          }          else if (frame is EasingDoubleKeyFrame)          {            frame.SetValue(EasingDoubleKeyFrame.KeyTimeProperty, newKeyTime);          }        }      }    }    /// <summary>    /// Updates the duration of the second keyframe of all the opacity animations    /// </summary>    /// <param name="key">Key of the dictionary</param>    /// <param name="newDuration">New value to be given to the duration value of the keyframes</param>    private void UpdateOpacityKeyTime(int key, Duration newDuration)    {      if (opKeyFrameMap.ContainsKey(key))      {        KeyTime newKeyTime = KeyTime.FromTimeSpan(newDuration.TimeSpan);        opKeyFrameMap[key].KeyFrameTime = newKeyTime;        foreach (var frame in opKeyFrameMap[key].KeyFrames)        {          if (frame is DiscreteDoubleKeyFrame)          {            frame.SetValue(DiscreteDoubleKeyFrame.KeyTimeProperty, newKeyTime);          }        }      }    }    /// <summary>    /// Updates the delay between consecutive timelines    /// </summary>    /// <param name="newDelay">Delay duration</param>    private void UpdateTimelineDelay(Duration newDelay)    {      Duration nextDelay = new Duration(TimeSpan.FromSeconds(0));      if (sb != null)      {        for (int i = 0; i < sb.Children.Count; i )        {          // The first five animations are for translation          // The next five animations are for opacity          if (i == 5)            nextDelay = newDelay;          else            nextDelay = newDelay;          DoubleAnimationUsingKeyFrames timeline = sb.Children[i] as DoubleAnimationUsingKeyFrames;          if (timeline != null)          {            timeline.SetValue(DoubleAnimationUsingKeyFrames.BeginTimeProperty, nextDelay.TimeSpan);          }        }      }    }    #endregion    #region IDisposable Implementation    /// <summary>    /// Releases all resources used by an instance of the FluidProgressBar class.    /// </summary>    /// <remarks>    /// This method calls the virtual Dispose(bool) method, passing in 'true', and then suppresses     /// finalization of the instance.    /// </remarks>    public void Dispose()    {      Dispose(true);      GC.SuppressFinalize(this);    }    /// <summary>    /// Releases unmanaged resources before an instance of the FluidProgressBar class is reclaimed by garbage collection.    /// </summary>    /// <remarks>    /// NOTE: Leave out the finalizer altogether if this class doesn't own unmanaged resources itself,     /// but leave the other methods exactly as they are.    /// This method releases unmanaged resources by calling the virtual Dispose(bool), passing in 'false'.    /// </remarks>    ~FluidProgressBar()    {      Dispose(false);    }    /// <summary>    /// Releases the unmanaged resources used by an instance of the FluidProgressBar class and optionally releases the managed resources.    /// </summary>    /// <param name="disposing">'true' to release both managed and unmanaged resources; 'false' to release only unmanaged resources.</param>    protected virtual void Dispose(bool disposing)    {      if (disposing)      {        // free managed resources here        this.SizeChanged -= OnSizeChanged;        this.Loaded -= OnLoaded;        this.IsVisibleChanged -= OnIsVisibleChanged;      }      // free native resources if there are any.    }    #endregion  }}

 
评论