diff --git a/src/Perspex.Controls/Perspex.Controls.csproj b/src/Perspex.Controls/Perspex.Controls.csproj
index 209290d807..d187e4a521 100644
--- a/src/Perspex.Controls/Perspex.Controls.csproj
+++ b/src/Perspex.Controls/Perspex.Controls.csproj
@@ -63,7 +63,9 @@
+
+
diff --git a/src/Perspex.Controls/Primitives/IScrollInfo.cs b/src/Perspex.Controls/Primitives/IScrollInfo.cs
new file mode 100644
index 0000000000..2d4c101a81
--- /dev/null
+++ b/src/Perspex.Controls/Primitives/IScrollInfo.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Perspex.Controls.Primitives
+{
+
+ public interface IScrollInfoBase
+ {
+ ///
+ /// ScrollOwner is the container that controls any scrollbars, headers, etc... that are dependant
+ /// on this IScrollInfo's properties. Implementers of IScrollInfo should call InvalidateScrollInfo()
+ /// on this object when properties change.
+ ///
+ ScrollViewer ScrollOwner { get; set; }
+
+ Rect MakeVisible(Visual visual, Rect rectangle);
+ }
+
+ public interface IVerticalScrollInfo : IScrollInfoBase
+ {
+ ///
+ /// VerticalOffset is the vertical offset into the scrolled content that represents the first unit visible.
+ ///
+ double VerticalOffset { get; set; }
+
+ ///
+ /// ExtentHeight contains the full vertical range of the scrolled content.
+ ///
+ double ExtentHeight { get; }
+
+ ///
+ /// ViewportHeight contains the currently visible vertical range of the scrolled content.
+ ///
+ double ViewportHeight { get; }
+
+ ///
+ /// This property indicates to the IScrollInfo whether or not it can scroll in the vertical given dimension.
+ ///
+ bool CanVerticallyScroll { get; set; }
+
+ void LineDown();
+
+ void LineUp();
+
+ void MouseWheelDown();
+
+ void MouseWheelUp();
+
+ void PageDown();
+
+ void PageUp();
+ }
+
+ public interface IHorizontalScrollInfo : IScrollInfoBase
+ {
+ ///
+ /// ExtentWidth contains the full horizontal range of the scrolled content.
+ ///
+ double ExtentWidth { get; }
+
+ ///
+ /// ViewportWidth contains the currently visible horizontal range of the scrolled content.
+ ///
+ double ViewportWidth { get; }
+
+ ///
+ /// HorizontalOffset is the horizontal offset into the scrolled content that represents the first unit visible.
+ ///
+ double HorizontalOffset { get; set; }
+
+ ///
+ /// This property indicates to the IScrollInfo whether or not it can scroll in the horizontal given dimension.
+ ///
+ bool CanHorizontallyScroll { get; set; }
+
+ void LineLeft();
+
+ void LineRight();
+
+ void MouseWheelLeft();
+
+ void MouseWheelRight();
+
+ void PageLeft();
+
+ void PageRight();
+ }
+
+ public interface IScrollInfo : IHorizontalScrollInfo, IVerticalScrollInfo
+ {
+ }
+}
diff --git a/src/Perspex.Controls/Primitives/ScrollInfoAdapter.cs b/src/Perspex.Controls/Primitives/ScrollInfoAdapter.cs
new file mode 100644
index 0000000000..0817e779f2
--- /dev/null
+++ b/src/Perspex.Controls/Primitives/ScrollInfoAdapter.cs
@@ -0,0 +1,124 @@
+namespace Perspex.Controls.Primitives
+{
+ public class ScrollInfoAdapter : IScrollInfo
+ {
+ private readonly IScrollInfoBase nfo;
+ public ScrollInfoAdapter(IScrollInfoBase nfo)
+ {
+ this.nfo = nfo;
+ }
+
+ public ScrollViewer ScrollOwner
+ {
+ get { return this.nfo.ScrollOwner; }
+ set { this.nfo.ScrollOwner = value; }
+ }
+
+ public double ExtentWidth => (this.nfo as IHorizontalScrollInfo)?.ExtentWidth ?? 0;
+
+ public double ViewportWidth => (this.nfo as IHorizontalScrollInfo)?.ViewportWidth ?? 0;
+
+ public double ExtentHeight => (this.nfo as IVerticalScrollInfo)?.ExtentHeight ?? 0;
+
+ public double ViewportHeight => (this.nfo as IVerticalScrollInfo)?.ViewportHeight ?? 0;
+
+ private double horizontalOffset;
+ public double HorizontalOffset
+ {
+ get
+ {
+ return (this.nfo as IHorizontalScrollInfo)?.HorizontalOffset ?? this.horizontalOffset;
+ }
+
+ set
+ {
+ var info = (this.nfo as IHorizontalScrollInfo);
+ if (info == null)
+ this.horizontalOffset = value;
+ else
+ info.HorizontalOffset = value;
+ }
+ }
+
+ private double verticalOffset;
+ public double VerticalOffset
+ {
+ get
+ {
+ return (this.nfo as IVerticalScrollInfo)?.VerticalOffset ?? this.verticalOffset;
+ }
+
+ set
+ {
+ var info = (this.nfo as IVerticalScrollInfo);
+ if (info == null)
+ this.verticalOffset = value;
+ else
+ info.VerticalOffset = value;
+ }
+ }
+
+ public void LineLeft() => (this.nfo as IHorizontalScrollInfo)?.LineLeft();
+
+ public void LineRight() => (this.nfo as IHorizontalScrollInfo)?.LineRight();
+
+ public void MouseWheelLeft() => (this.nfo as IHorizontalScrollInfo)?.MouseWheelLeft();
+
+ public void MouseWheelRight() => (this.nfo as IHorizontalScrollInfo)?.MouseWheelRight();
+
+ public void PageLeft() => (this.nfo as IHorizontalScrollInfo)?.PageLeft();
+
+ public Rect MakeVisible(Visual visual, Rect rectangle) => this.nfo.MakeVisible(visual, rectangle);
+
+ public void PageRight() => (this.nfo as IHorizontalScrollInfo)?.PageRight();
+
+ public void LineDown() => (this.nfo as IVerticalScrollInfo)?.LineDown();
+
+ public void LineUp() => (this.nfo as IVerticalScrollInfo)?.LineUp();
+
+ public void MouseWheelDown() => (this.nfo as IVerticalScrollInfo)?.MouseWheelDown();
+
+ public void MouseWheelUp() => (this.nfo as IVerticalScrollInfo)?.MouseWheelUp();
+
+ public void PageDown() => (this.nfo as IVerticalScrollInfo)?.PageDown();
+
+ public void PageUp() => (this.nfo as IVerticalScrollInfo)?.PageUp();
+
+ private bool canVerticallyScroll;
+ public bool CanVerticallyScroll
+ {
+ get
+ {
+ return (this.nfo as IVerticalScrollInfo)?.CanVerticallyScroll ?? this.canVerticallyScroll;
+ }
+
+ set
+ {
+ var info = (this.nfo as IVerticalScrollInfo);
+ if (info == null)
+ this.canVerticallyScroll = value;
+ else
+ info.CanVerticallyScroll = value;
+ }
+ }
+
+ private bool canHorizontallyScroll;
+ public bool CanHorizontallyScroll
+ {
+ get
+ {
+ return (this.nfo as IHorizontalScrollInfo)?.CanHorizontallyScroll ?? this.canHorizontallyScroll;
+ }
+
+ set
+ {
+ var info = (this.nfo as IHorizontalScrollInfo);
+ if (info == null)
+ this.canHorizontallyScroll = value;
+ else
+ info.CanHorizontallyScroll = value;
+ }
+ }
+
+ }
+}