private void ScrollToVerticalOffset(double delta, bool isAnimationEnabled) { var scrollViewer = this.GetScrollViewer(); if (scrollViewer == null) { return; } var time = this.AnimationTime; if (time <= 0 || !isAnimationEnabled) { // no animation scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + delta); return; } var animation = new DoubleAnimation() { From = 0, To = delta, EasingFunction = new PowerEase() { EasingMode = EasingMode.EaseInOut, Power = 1.2 }, Duration = new Duration(TimeSpan.FromMilliseconds(time)), }; var target = new SingleValueAnimator <double>(); var id = this.idCount++; target.ValueChanged += (o, e) => this.Animated(scrollViewer, id, target, e); //var startTime = DateTime.Now.Ticks; animation.Completed += (o, e) => { //Debug.WriteLine(DateTime.Now.Ticks - startTime); this.animatingObjects.Remove(id); }; //Debug.WriteLine($"{DateTime.Now.Ticks}, {this.animatingObjects.Count}"); target.BeginAnimation(SingleValueAnimator <double> .ValueProperty, animation); }
/// <summary> /// アニメーション中 /// </summary> /// <param name="scrollViewer"></param> /// <param name="id"></param> /// <param name="e"></param> private void Animated (ScrollViewer scrollViewer, int id, SingleValueAnimator <double> target, DependencyPropertyChangedEventArgs e) { this.request.Enqueue(new ScrollRequestContainer() { OldValue = (double)e.OldValue, NewValue = (double)e.NewValue, Id = id, }); this.animatingObjects[id] = target; //リクエストが溜まっていない間はスクロールしない if (request.Count < this.animatingObjects.Count) { //Debug.WriteLine($"request:{request.Count},animating:{this.animatingObjects.Count}"); return; } var items = this.request.ToArray(); this.request.Clear(); var oldValue = 0.0; var newValue = 0.0; foreach (var item in items) { oldValue += item.OldValue; newValue += item.NewValue; } //var oldValue = items.Sum(x => x.OldValue); //var newValue = items.Sum(x => x.NewValue); var ids = items.Select(x => x.Id).Distinct().ToArray(); if (this.prevActedIds != null) { //動いていないアニメーションが検出された var actedIds = this.prevActedIds.Concat(ids).Distinct().ToArray(); this.animatingObjects .Where(x => !actedIds.Contains(x.Key)) .ToArray() .ForEach(x => { this.animatingObjects.Remove(x.Key); Debug.WriteLine($"aborted animation is detected:{x.Key}"); }); this.prevActedIds = null; } else { if (ids.Length != items.Length) { //Id被り=動いていないアニメーションがある this.prevActedIds = ids; Debug.WriteLine("animation id is repeated"); } else { this.prevActedIds = null; } } var b = scrollViewer.VerticalOffset - oldValue; scrollViewer.ScrollToVerticalOffset(b + newValue); //Debug.WriteLine($"{DateTime.Now.Ticks}, {newValue - oldValue}, {items.Length}"); }