diff --git a/samples/XamlTestApplicationPcl/TestScrollable.cs b/samples/XamlTestApplicationPcl/TestScrollable.cs
index 76f4cdd106..1f0961af27 100644
--- a/samples/XamlTestApplicationPcl/TestScrollable.cs
+++ b/samples/XamlTestApplicationPcl/TestScrollable.cs
@@ -3,6 +3,7 @@ using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Media;
+using Avalonia.VisualTree;
namespace XamlTestApplication
{
@@ -54,6 +55,31 @@ namespace XamlTestApplication
}
}
+ public override void Render(DrawingContext context)
+ {
+ var y = 0.0;
+
+ for (var i = (int)_offset.Y; i < itemCount; ++i)
+ {
+ using (var line = new FormattedText(
+ "Item " + (i + 1),
+ TextBlock.GetFontFamily(this),
+ TextBlock.GetFontSize(this),
+ TextBlock.GetFontStyle(this),
+ TextAlignment.Left,
+ TextBlock.GetFontWeight(this)))
+ {
+ context.DrawText(Brushes.Black, new Point(-_offset.X, y), line);
+ y += _lineSize.Height;
+ }
+ }
+ }
+
+ public bool BringIntoView(IVisual target, Rect targetRect)
+ {
+ throw new NotImplementedException();
+ }
+
protected override Size MeasureOverride(Size availableSize)
{
using (var line = new FormattedText(
@@ -77,25 +103,5 @@ namespace XamlTestApplication
InvalidateScroll?.Invoke();
return finalSize;
}
-
- public override void Render(DrawingContext context)
- {
- var y = 0.0;
-
- for (var i = (int)_offset.Y; i < itemCount; ++i)
- {
- using (var line = new FormattedText(
- "Item " + (i + 1),
- TextBlock.GetFontFamily(this),
- TextBlock.GetFontSize(this),
- TextBlock.GetFontStyle(this),
- TextAlignment.Left,
- TextBlock.GetFontWeight(this)))
- {
- context.DrawText(Brushes.Black, new Point(-_offset.X, y), line);
- y += _lineSize.Height;
- }
- }
- }
}
}
\ No newline at end of file
diff --git a/src/Avalonia.Controls/Presenters/ItemVirtualizer.cs b/src/Avalonia.Controls/Presenters/ItemVirtualizer.cs
index b45ed8065b..63d4503df7 100644
--- a/src/Avalonia.Controls/Presenters/ItemVirtualizer.cs
+++ b/src/Avalonia.Controls/Presenters/ItemVirtualizer.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections;
using System.Collections.Specialized;
using Avalonia.Controls.Primitives;
+using Avalonia.VisualTree;
namespace Avalonia.Controls.Presenters
{
@@ -45,6 +46,11 @@ namespace Avalonia.Controls.Presenters
public abstract void Arranging(Size finalSize);
+ public virtual bool BringIntoView(IVisual target, Rect targetRect)
+ {
+ return false;
+ }
+
public virtual void ItemsChanged(IEnumerable items, NotifyCollectionChangedEventArgs e)
{
Items = items;
diff --git a/src/Avalonia.Controls/Presenters/ItemsPresenter.cs b/src/Avalonia.Controls/Presenters/ItemsPresenter.cs
index fc20add96c..86636b1837 100644
--- a/src/Avalonia.Controls/Presenters/ItemsPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/ItemsPresenter.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Specialized;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
+using Avalonia.VisualTree;
using static Avalonia.Utilities.MathUtilities;
namespace Avalonia.Controls.Presenters
@@ -71,6 +72,12 @@ namespace Avalonia.Controls.Presenters
///
Size IScrollable.PageScrollSize => new Size(0, 1);
+ ///
+ bool IScrollable.BringIntoView(IVisual target, Rect targetRect)
+ {
+ return _virtualizer?.BringIntoView(target, targetRect) ?? false;
+ }
+
///
protected override Size ArrangeOverride(Size finalSize)
{
diff --git a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs
index 5d295d7fc8..4c7a00f6fd 100644
--- a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs
@@ -117,6 +117,13 @@ namespace Avalonia.Controls.Presenters
return false;
}
+ var scrollable = Child as IScrollable;
+
+ if (scrollable?.IsLogicalScrollEnabled == true)
+ {
+ return scrollable.BringIntoView(target, targetRect);
+ }
+
var transform = target.TransformToVisual(Child);
if (transform == null)
diff --git a/src/Avalonia.Controls/Primitives/IScrollable.cs b/src/Avalonia.Controls/Primitives/IScrollable.cs
index d37d1fdcca..b9155054b8 100644
--- a/src/Avalonia.Controls/Primitives/IScrollable.cs
+++ b/src/Avalonia.Controls/Primitives/IScrollable.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
+using Avalonia.VisualTree;
namespace Avalonia.Controls.Primitives
{
@@ -62,5 +63,13 @@ namespace Avalonia.Controls.Primitives
/// Gets the size to page by, in logical units.
///
Size PageScrollSize { get; }
+
+ ///
+ /// 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.
+ bool BringIntoView(IVisual target, Rect targetRect);
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ScrollContentPresenterTests_IScrollable.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ScrollContentPresenterTests_IScrollable.cs
index 1aea155eaa..a690522e89 100644
--- a/tests/Avalonia.Controls.UnitTests/Presenters/ScrollContentPresenterTests_IScrollable.cs
+++ b/tests/Avalonia.Controls.UnitTests/Presenters/ScrollContentPresenterTests_IScrollable.cs
@@ -6,6 +6,7 @@ using System.Reactive.Linq;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Layout;
+using Avalonia.VisualTree;
using Xunit;
namespace Avalonia.Controls.UnitTests
@@ -236,7 +237,6 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(new Rect(0, 0, 100, 100), scrollable.Bounds);
}
-
private class TestScrollable : Control, IScrollable
{
private Size _extent;
@@ -293,6 +293,11 @@ namespace Avalonia.Controls.UnitTests
}
}
+ public bool BringIntoView(IVisual target, Rect targetRect)
+ {
+ throw new NotImplementedException();
+ }
+
protected override Size MeasureOverride(Size availableSize)
{
AvailableSize = availableSize;