void OnScrollToRequested(object sender, ScrollToRequestedEventArgs e) { if (_animatable == null && e.ShouldAnimate) { _animatable = new Animatable(); } ScrollToPosition position = e.Position; double x = e.ScrollX; double y = e.ScrollY; if (e.Mode == ScrollToMode.Element) { Point itemPosition = Controller.GetScrollPositionForElement(e.Element as VisualElement, e.Position); x = itemPosition.X; y = itemPosition.Y; } if (Control.VerticalOffset == y && Control.HorizontalOffset == x) { return; } if (e.ShouldAnimate) { var animation = new Animation(v => { UpdateScrollOffset(GetDistance(Control.ViewportWidth, x, v), GetDistance(Control.ViewportHeight, y, v)); }); animation.Commit(_animatable, "ScrollTo", length: 500, easing: Easing.CubicInOut, finished: (v, d) => { UpdateScrollOffset(x, y); Controller.SendScrollFinished(); }); } else { UpdateScrollOffset(x, y); Controller.SendScrollFinished(); } }
void OnScrollToRequested(object sender, ScrollToRequestedEventArgs e) { if (_animatable == null && e.ShouldAnimate) { _animatable = new Animatable(); } if (_viewport == null) { // Making sure we're actually loaded if (VisualTreeHelper.GetChildrenCount(_listBox) == 0) { RoutedEventHandler handler = null; handler = (o, args) => { Control.Loaded -= handler; OnScrollToRequested(sender, e); }; Control.Loaded += handler; return; } _viewport = (ViewportControl)VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(_listBox, 0), 0), 0); if (_viewport.Viewport.Bottom == 0) { EventHandler <ViewportChangedEventArgs> viewportChanged = null; viewportChanged = (o, args) => { if (_viewport.Viewport.Bottom == 0) { return; } _viewport.ViewportChanged -= viewportChanged; OnScrollToRequested(sender, e); }; _viewport.ViewportChanged += viewportChanged; return; } } double y = 0; double targetHeight = 0; double targetHeaderHeight = 0; var templateReusables = new Dictionary <System.Windows.DataTemplate, FrameworkElement>(); var found = false; if (Element.IsGroupingEnabled) { for (var g = 0; g < Element.TemplatedItems.Count; g++) { if (found) { break; } TemplatedItemsList <ItemsView <Cell>, Cell> til = Element.TemplatedItems.GetGroup(g); double headerHeight = GetHeight(templateReusables, Control.GroupHeaderTemplate, til); y += headerHeight; for (var i = 0; i < til.Count; i++) { Cell cell = til[i]; double contentHeight = GetHeight(templateReusables, Control.ItemTemplate, cell); if ((ReferenceEquals(til.BindingContext, e.Group) || e.Group == null) && ReferenceEquals(cell.BindingContext, e.Item)) { targetHeaderHeight = headerHeight; targetHeight = contentHeight; found = true; break; } y += contentHeight; } } } else { for (var i = 0; i < Element.TemplatedItems.Count; i++) { Cell cell = Element.TemplatedItems[i]; double height = GetHeight(templateReusables, Control.ItemTemplate, cell); if (ReferenceEquals(cell.BindingContext, e.Item)) { found = true; targetHeight = height; break; } y += height; } } if (!found) { return; } ScrollToPosition position = e.Position; if (position == ScrollToPosition.MakeVisible) { if (y >= _viewport.Viewport.Top && y <= _viewport.Viewport.Bottom) { return; } if (y > _viewport.Viewport.Bottom) { position = ScrollToPosition.End; } else { position = ScrollToPosition.Start; } } if (position == ScrollToPosition.Start && Element.IsGroupingEnabled) { y = y - targetHeaderHeight; } else if (position == ScrollToPosition.Center) { y = y - (_viewport.ActualHeight / 2 + targetHeight / 2); } else if (position == ScrollToPosition.End) { y = y - _viewport.ActualHeight + targetHeight; } double startY = _viewport.Viewport.Y; double distance = y - startY; if (e.ShouldAnimate) { var animation = new Animation(v => { _viewport.SetViewportOrigin(new System.Windows.Point(0, startY + distance * v)); }); animation.Commit(_animatable, "ScrollTo", length: 500, easing: Easing.CubicInOut); } else { _viewport.SetViewportOrigin(new System.Windows.Point(0, y)); } }