/// <summary> /// Scrolls to the desired index, starting from the provided visual item. /// </summary> /// <param name="item">The visual item to start from.</param> /// <param name="to">The target index to scroll to.</param> private void ScrollToIndex(LoopingListItem item, int to) { if (!this.IsInitialized()) { return; } int from = item.LogicalIndex; if (item.LogicalIndex == to) { this.BringIntoView(to); return; } int indexOffset = Math.Abs(from - to); int pivotIndex = this.logicalCount / 2; int sign = Math.Sign(from - to); if (indexOffset > pivotIndex) { indexOffset = this.logicalCount - indexOffset; sign *= -1; } double offset = this.visualOffset + (sign * indexOffset * this.itemLength); this.scrollState = LoopingPanelScrollState.ScrollingToIndex; this.AnimateVerticalOffset(offset); }
/// <summary> /// Ensures that the visual item, associated with the specified logical index is currently displayed. /// </summary> /// <param name="logicalIndex"></param> /// <param name="animate">True to perform animated scrolling, false otherwise.</param> private void BringIntoView(int logicalIndex, bool animate) { // no visual children yet if (this.items.Count == 0) { return; } if (logicalIndex < 0 || logicalIndex >= this.logicalCount) { return; } double offset = this.CalculateOffset(logicalIndex); if (animate) { this.scrollState = LoopingPanelScrollState.ScrollingToIndex; this.AnimateVerticalOffset(offset); } else { this.UpdateWheel(offset, false); } }
/// <summary> /// Applies the specified offset as current. /// </summary> /// <param name="offset">The desired offset.</param> /// <param name="duration">The duration of the animation used to apply the offset.</param> /// <param name="ease">The easing function that describes animation interpolation.</param> internal void SetVerticalOffset(double offset, Duration duration, EasingFunctionBase ease) { if (!this.IsInitialized()) { return; } this.scrollState = LoopingPanelScrollState.Scrolling; this.AnimateVerticalOffset(duration, ease, offset); }
/// <summary> /// Stops the vertical offset animation (if running). /// </summary> internal void StopOffsetAnimation(bool raiseCompleted) { LoopingPanelScrollState currentState = this.scrollState; this.scrollState = LoopingPanelScrollState.NotScrolling; this.animating = false; this.offsetStoryboard.Stop(); if (raiseCompleted && currentState != LoopingPanelScrollState.NotScrolling) { this.OnScrollCompleted(currentState); } }
private void OnOffsetAnimationCompleted(object sender, object args) { if (this.scrollState == LoopingPanelScrollState.NotScrolling) { return; } LoopingPanelScrollState previousState = this.scrollState; this.animating = false; this.offsetStoryboard.Stop(); this.OnScrollCompleted(previousState); }
internal void Scroll(double amount) { if (!this.IsInitialized()) { return; } if (this.animating) { this.StopOffsetAnimation(false); } this.scrollState = LoopingPanelScrollState.Scrolling; this.UpdateWheel(this.visualOffset + amount, false); }
/// <summary> /// Notifies that a scroll operation has completed. /// </summary> /// <param name="previousState">The state the panel was in before the scrolling ended.</param> private void OnScrollCompleted(LoopingPanelScrollState previousState) { this.scrollState = LoopingPanelScrollState.NotScrolling; if (!this.isCentered) { return; } if (previousState == LoopingPanelScrollState.Scrolling || previousState == LoopingPanelScrollState.ScrollingToIndex) { this.CenterMiddleItem(previousState != LoopingPanelScrollState.ScrollingToIndex, true); } }
/// <summary> /// Ensures that the visual item, associated with the specified logical index is currently displayed. /// </summary> /// <param name="logicalIndex">The logical index of the item.</param> /// <param name="visualIndex">The visual index of the item.</param> /// <param name="animate">True to perform animated scrolling, false otherwise.</param> private void BringIntoView(int logicalIndex, int visualIndex, bool animate) { // no visual children yet if (this.items.Count == 0) { return; } if (logicalIndex < 0 || logicalIndex >= this.logicalCount) { return; } double offset; if (this.IsIndexInView(logicalIndex) && visualIndex >= 0) { offset = this.CalculateVisualOffset(visualIndex, this.visualIndexChain[0]); } else { offset = this.CalculateLogicalOffset(logicalIndex, this.topLogicalIndex); } if (animate) { this.scrollState = LoopingPanelScrollState.ScrollingToIndex; this.AnimateVerticalOffset(offset); } else { this.UpdateWheel(offset, false); this.UpdateLayout(); // Force items to be remeasured as occasionalli there is no measure for items and they desapear. this.InvalidateMeasure(); } }