diff --git a/src/Perspex.Controls/Presenters/ScrollContentPresenter.cs b/src/Perspex.Controls/Presenters/ScrollContentPresenter.cs index f2ff1e3d5d..5ee9cc160d 100644 --- a/src/Perspex.Controls/Presenters/ScrollContentPresenter.cs +++ b/src/Perspex.Controls/Presenters/ScrollContentPresenter.cs @@ -9,22 +9,40 @@ using Perspex.VisualTree; namespace Perspex.Controls.Presenters { + /// + /// Presents a scrolling view of content inside a . + /// public class ScrollContentPresenter : ContentPresenter, IPresenter { + /// + /// Defines the property. + /// public static readonly PerspexProperty ExtentProperty = ScrollViewer.ExtentProperty.AddOwner(); + /// + /// Defines the property. + /// public static readonly PerspexProperty OffsetProperty = ScrollViewer.OffsetProperty.AddOwner(); + /// + /// Defines the property. + /// public static readonly PerspexProperty ViewportProperty = ScrollViewer.ViewportProperty.AddOwner(); + /// + /// Defines the property. + /// public static readonly PerspexProperty CanScrollHorizontallyProperty = PerspexProperty.Register("CanScrollHorizontally", true); private Size _measuredExtent; + /// + /// Initializes static members of the class. + /// static ScrollContentPresenter() { ClipToBoundsProperty.OverrideDefaultValue(typeof(ScrollContentPresenter), true); @@ -32,31 +50,88 @@ namespace Perspex.Controls.Presenters AffectsArrange(OffsetProperty); } + /// + /// Initializes a new instance of the class. + /// public ScrollContentPresenter() { AddHandler(RequestBringIntoViewEvent, BringIntoViewRequested); } + /// + /// Gets the extent of the scrollable content. + /// public Size Extent { get { return GetValue(ExtentProperty); } private set { SetValue(ExtentProperty, value); } } + /// + /// Gets or sets the current scroll offset. + /// public Vector Offset { get { return GetValue(OffsetProperty); } set { SetValue(OffsetProperty, value); } } + /// + /// Gets the size of the viewport on the scrollable content. + /// public Size Viewport { get { return GetValue(ViewportProperty); } private set { SetValue(ViewportProperty, value); } } + /// + /// Gets a value indicating whether the content can be scrolled horizontally. + /// public bool CanScrollHorizontally => GetValue(CanScrollHorizontallyProperty); + /// + /// Attempts to bring a portion of the target visual into view by scrolling the content. + /// + /// The target visual. + /// The portion of the target visual to bring into view. + /// True if the scroll offset was changed; otherwise false. + public bool BringDescendentIntoView(IVisual target, Rect targetRect) + { + var transform = target.TransformToVisual(this.GetVisualChildren().Single()); + var rect = targetRect * transform; + var offset = Offset; + var result = false; + + if (rect.Bottom > offset.Y + Viewport.Height) + { + offset = offset.WithY(rect.Bottom - Viewport.Height); + result = true; + } + + if (rect.Y < offset.Y) + { + offset = offset.WithY(rect.Y); + result = true; + } + + if (rect.Right > offset.X + Viewport.Width) + { + offset = offset.WithX(rect.Right - Viewport.Width); + result = true; + } + + if (rect.X < offset.X) + { + offset = offset.WithX(rect.X); + result = true; + } + + Offset = offset; + return result; + } + + /// protected override Size MeasureOverride(Size availableSize) { var content = Content as ILayoutable; @@ -81,6 +156,7 @@ namespace Perspex.Controls.Presenters } } + /// protected override Size ArrangeOverride(Size finalSize) { var child = this.GetVisualChildren().SingleOrDefault() as ILayoutable; @@ -100,6 +176,7 @@ namespace Perspex.Controls.Presenters return new Size(); } + /// protected override void OnPointerWheelChanged(PointerWheelEventArgs e) { if (Extent.Height > Viewport.Height) @@ -114,35 +191,7 @@ namespace Perspex.Controls.Presenters private void BringIntoViewRequested(object sender, RequestBringIntoViewEventArgs e) { - var transform = e.TargetObject.TransformToVisual(this.GetVisualChildren().Single()); - var rect = e.TargetRect * transform; - var offset = Offset; - - if (rect.Bottom > offset.Y + Viewport.Height) - { - offset = offset.WithY(rect.Bottom - Viewport.Height); - e.Handled = true; - } - - if (rect.Y < offset.Y) - { - offset = offset.WithY(rect.Y); - e.Handled = true; - } - - if (rect.Right > offset.X + Viewport.Width) - { - offset = offset.WithX(rect.Right - Viewport.Width); - e.Handled = true; - } - - if (rect.X < offset.X) - { - offset = offset.WithX(rect.X); - e.Handled = true; - } - - Offset = offset; + e.Handled = BringDescendentIntoView(e.TargetObject, e.TargetRect); } private static Vector ValidateOffset(ScrollContentPresenter o, Vector value)