public override bool Equals(object obj) { ObjectPropertyPair next = obj as ObjectPropertyPair; if (next == null) { return(false); } return(this.TargetName == next.TargetName && this.TargetProperty == next.TargetProperty); }
/// <summary> /// This method should be called immediately after InitializeComponent() in most cases, or whenever you modify the animation parameters. /// </summary> public void Render() { Dictionary <ObjectPropertyPair, AnimationTimeline> index = new Dictionary <ObjectPropertyPair, AnimationTimeline>(); Frames.OrderBy <Frame, KeyTime>(delegate(Frame target) { return(target.KeyTime); }); // The trick here is to turn time-dominant form into property-dominant form. foreach (Frame frame in Frames) { foreach (Setter setter in frame) { ObjectPropertyPair pair = new ObjectPropertyPair(setter.TargetName, setter.Property); AnimationTimeline animation; if (!index.ContainsKey(pair)) { animation = CreateAnimationFromType(setter.Property.PropertyType); Storyboard.SetTargetName(animation, setter.TargetName); Storyboard.SetTargetProperty(animation, new PropertyPath(setter.Property)); animation.Duration = this.Duration; index.Add(pair, animation); } animation = index[pair]; ((IKeyFrameAnimation)animation).KeyFrames.Add(CreateKeyFrameFromType(setter.Property.PropertyType, setter.Value, frame.KeyTime)); } } foreach (AnimationTimeline animation in index.Values) { if (LoopAnimation) { // Finally, tie each animation closed by projecting its initial frame into the future so that interpolations will be smooth. IKeyFrame firstFrame = (IKeyFrame)((IKeyFrameAnimation)animation).KeyFrames[0]; // Assume there will always be at least one frame. ((IKeyFrameAnimation)animation).KeyFrames.Add(CreateKeyFrameFromType(firstFrame.Value.GetType(), firstFrame.Value.ToString(), KeyTime.FromTimeSpan(firstFrame.KeyTime.TimeSpan + this.Duration.TimeSpan))); } this.Children.Add(animation); } }