浏览代码

merged latest

Tig 11 月之前
父节点
当前提交
6c56b99a06

+ 6 - 6
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -1811,12 +1811,6 @@ internal class WindowsDriver : ConsoleDriver
         int delay = startDelay;
         int delay = startDelay;
         while (_isButtonPressed)
         while (_isButtonPressed)
         {
         {
-            var me = new MouseEvent
-            {
-                Position = _pointMove,
-                Flags = mouseFlag
-            };
-
             // TODO: This makes ConsoleDriver dependent on Application, which is not ideal. This should be moved to Application.
             // TODO: This makes ConsoleDriver dependent on Application, which is not ideal. This should be moved to Application.
             View view = Application.WantContinuousButtonPressedView;
             View view = Application.WantContinuousButtonPressedView;
 
 
@@ -1831,6 +1825,12 @@ internal class WindowsDriver : ConsoleDriver
             }
             }
             await Task.Delay (delay);
             await Task.Delay (delay);
 
 
+            var me = new MouseEvent
+            {
+                Position = _pointMove,
+                Flags = mouseFlag
+            };
+
             //Debug.WriteLine($"ProcessContinuousButtonPressedAsync: {view}");
             //Debug.WriteLine($"ProcessContinuousButtonPressedAsync: {view}");
             if (_isButtonPressed && (mouseFlag & MouseFlags.ReportMousePosition) == 0)
             if (_isButtonPressed && (mouseFlag & MouseFlags.ReportMousePosition) == 0)
             {
             {

+ 60 - 8
Terminal.Gui/Views/Scroll/Scroll.cs

@@ -33,6 +33,7 @@ public class Scroll : View
     private Orientation _orientation;
     private Orientation _orientation;
     private int _position;
     private int _position;
     private int _size;
     private int _size;
+    private bool _keepContentInAllViewport = true;
 
 
     /// <inheritdoc/>
     /// <inheritdoc/>
     public override void EndInit ()
     public override void EndInit ()
@@ -42,6 +43,42 @@ public class Scroll : View
         AdjustScroll ();
         AdjustScroll ();
     }
     }
 
 
+    /// <summary>Get or sets if the view-port is kept in all visible area of this <see cref="Scroll"/></summary>
+    public bool KeepContentInAllViewport
+    {
+        get => _keepContentInAllViewport;
+        set
+        {
+            if (_keepContentInAllViewport != value)
+            {
+                _keepContentInAllViewport = value;
+                var pos = 0;
+
+                if (value
+                    && Orientation == Orientation.Horizontal
+                    && _position + (SuperViewAsScrollBar is { } ? SuperViewAsScrollBar.GetContentSize ().Width : GetContentSize ().Width) > Size)
+                {
+                    pos = Size - (SuperViewAsScrollBar is { } ? SuperViewAsScrollBar.GetContentSize ().Width : GetContentSize ().Width);
+                }
+
+                if (value
+                    && Orientation == Orientation.Vertical
+                    && _position + (SuperViewAsScrollBar is { } ? SuperViewAsScrollBar.GetContentSize ().Height : GetContentSize ().Height) > Size)
+                {
+                    pos = _size - (SuperViewAsScrollBar is { } ? SuperViewAsScrollBar.GetContentSize ().Height : GetContentSize ().Height);
+                }
+
+                if (pos != 0)
+                {
+                    Position = pos;
+                }
+
+                SetNeedsDisplay ();
+                AdjustScroll ();
+            }
+        }
+    }
+
     /// <summary>
     /// <summary>
     ///     Gets or sets if the Scroll is oriented vertically or horizontally.
     ///     Gets or sets if the Scroll is oriented vertically or horizontally.
     /// </summary>
     /// </summary>
@@ -74,21 +111,21 @@ public class Scroll : View
                 SetRelativeLayout (SuperViewAsScrollBar.Frame.Size);
                 SetRelativeLayout (SuperViewAsScrollBar.Frame.Size);
             }
             }
 
 
-            int barSize = BarSize;
+            int pos = SetPosition (value);
 
 
-            if (value + barSize > Size)
+            if (pos == _position)
             {
             {
                 return;
                 return;
             }
             }
 
 
-            CancelEventArgs<int> args = OnPositionChanging (_position, value);
+            CancelEventArgs<int> args = OnPositionChanging (_position, pos);
 
 
             if (args.Cancel)
             if (args.Cancel)
             {
             {
                 return;
                 return;
             }
             }
 
 
-            _position = value;
+            _position = pos;
 
 
             AdjustScroll ();
             AdjustScroll ();
 
 
@@ -113,6 +150,11 @@ public class Scroll : View
         get => _size;
         get => _size;
         set
         set
         {
         {
+            if (value == _size || value < 0)
+            {
+                return;
+            }
+
             _size = value;
             _size = value;
             OnSizeChanged (_size);
             OnSizeChanged (_size);
             AdjustScroll ();
             AdjustScroll ();
@@ -140,14 +182,12 @@ public class Scroll : View
         }
         }
         else if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Pressed) && location > sliderPos.end)
         else if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Pressed) && location > sliderPos.end)
         {
         {
-            int distance = location - sliderPos.end;
-            int scrollAmount = (int)((double)distance / barSize * (Size - barSize));
-            Position = Math.Min (Position + scrollAmount, Size - barSize);
+            Position = Math.Min (Position + barSize, Size - barSize + (KeepContentInAllViewport ? 0 : barSize));
         }
         }
         else if ((mouseEvent.Flags == MouseFlags.WheeledDown && Orientation == Orientation.Vertical)
         else if ((mouseEvent.Flags == MouseFlags.WheeledDown && Orientation == Orientation.Vertical)
                  || (mouseEvent.Flags == MouseFlags.WheeledRight && Orientation == Orientation.Horizontal))
                  || (mouseEvent.Flags == MouseFlags.WheeledRight && Orientation == Orientation.Horizontal))
         {
         {
-            Position = Math.Min (Position + 1, Size - barSize);
+            Position = Math.Min (Position + 1, Size - barSize + (KeepContentInAllViewport ? 0 : barSize));
         }
         }
         else if ((mouseEvent.Flags == MouseFlags.WheeledUp && Orientation == Orientation.Vertical)
         else if ((mouseEvent.Flags == MouseFlags.WheeledUp && Orientation == Orientation.Vertical)
                  || (mouseEvent.Flags == MouseFlags.WheeledLeft && Orientation == Orientation.Horizontal))
                  || (mouseEvent.Flags == MouseFlags.WheeledLeft && Orientation == Orientation.Horizontal))
@@ -209,6 +249,18 @@ public class Scroll : View
 
 
     private int BarSize => Orientation == Orientation.Vertical ? Viewport.Height : Viewport.Width;
     private int BarSize => Orientation == Orientation.Vertical ? Viewport.Height : Viewport.Width;
 
 
+    private int SetPosition (int position)
+    {
+        int barSize = BarSize;
+
+        if (position + barSize > Size)
+        {
+            return KeepContentInAllViewport ? Math.Max (Size - barSize, 0) : Math.Max (Size - 1, 0);
+        }
+
+        return position;
+    }
+
     private void SetScrollText ()
     private void SetScrollText ()
     {
     {
         TextDirection = Orientation == Orientation.Vertical ? TextDirection.TopBottom_LeftRight : TextDirection.LeftRight_TopBottom;
         TextDirection = Orientation == Orientation.Vertical ? TextDirection.TopBottom_LeftRight : TextDirection.LeftRight_TopBottom;

+ 11 - 1
Terminal.Gui/Views/Scroll/ScrollBar.cs

@@ -38,7 +38,10 @@ public class ScrollBar : View
     private bool _autoHide = true;
     private bool _autoHide = true;
     private bool _showScrollIndicator = true;
     private bool _showScrollIndicator = true;
 
 
-    /// <summary>Gets or sets whether <see cref="View.Visible"/> will be set to <see langword="false"/> if the dimension of the scroll bar is greater than or equal to <see cref="Size"/>.</summary>
+    /// <summary>
+    ///     Gets or sets whether <see cref="View.Visible"/> will be set to <see langword="false"/> if the dimension of the
+    ///     scroll bar is greater than or equal to <see cref="Size"/>.
+    /// </summary>
     public bool AutoHide
     public bool AutoHide
     {
     {
         get => _autoHide;
         get => _autoHide;
@@ -52,6 +55,13 @@ public class ScrollBar : View
         }
         }
     }
     }
 
 
+    /// <summary>Get or sets if the view-port is kept in all visible area of this <see cref="ScrollBar"/></summary>
+    public bool KeepContentInAllViewport
+    {
+        get => _scroll.KeepContentInAllViewport;
+        set => _scroll.KeepContentInAllViewport = value;
+    }
+
     /// <summary>Gets or sets if a scrollbar is vertical or horizontal.</summary>
     /// <summary>Gets or sets if a scrollbar is vertical or horizontal.</summary>
     public Orientation Orientation
     public Orientation Orientation
     {
     {

+ 22 - 8
Terminal.Gui/Views/Scroll/ScrollSlider.cs

@@ -28,8 +28,12 @@ internal class ScrollSlider : View
 
 
         SetContentSize (
         SetContentSize (
                         new (
                         new (
-                             SuperViewAsScroll.Orientation == Orientation.Vertical ? SuperViewAsScroll.GetContentSize ().Width : sliderLocationAndDimension.Dimension,
-                             SuperViewAsScroll.Orientation == Orientation.Vertical ? sliderLocationAndDimension.Dimension : SuperViewAsScroll.GetContentSize ().Height
+                             SuperViewAsScroll.Orientation == Orientation.Vertical
+                                 ? SuperViewAsScroll.GetContentSize ().Width
+                                 : sliderLocationAndDimension.Dimension,
+                             SuperViewAsScroll.Orientation == Orientation.Vertical
+                                 ? sliderLocationAndDimension.Dimension
+                                 : SuperViewAsScroll.GetContentSize ().Height
                             ));
                             ));
         SetSliderText ();
         SetSliderText ();
     }
     }
@@ -85,8 +89,13 @@ internal class ScrollSlider : View
         {
         {
             if (SuperViewAsScroll.Orientation == Orientation.Vertical)
             if (SuperViewAsScroll.Orientation == Orientation.Vertical)
             {
             {
-                Y = Frame.Y + offset < 0 ? 0 :
-                    Frame.Y + offset + Frame.Height > barSize ? Math.Max (barSize - Frame.Height, 0) : Frame.Y + offset;
+                Y = Frame.Y + offset < 0
+                        ? 0
+                        :
+                        Frame.Y + offset + Frame.Height > barSize + (SuperViewAsScroll.KeepContentInAllViewport ? 0 : barSize)
+                            ?
+                            Math.Max (barSize - Frame.Height, 0)
+                            : Frame.Y + offset;
 
 
                 SuperViewAsScroll.Position = GetPositionFromSliderLocation (Frame.Y);
                 SuperViewAsScroll.Position = GetPositionFromSliderLocation (Frame.Y);
             }
             }
@@ -144,14 +153,16 @@ internal class ScrollSlider : View
             return 0;
             return 0;
         }
         }
 
 
-        int scrollSize = SuperViewAsScroll.Orientation == Orientation.Vertical ? SuperViewAsScroll.GetContentSize ().Height : SuperViewAsScroll.GetContentSize ().Width;
+        int scrollSize = SuperViewAsScroll.Orientation == Orientation.Vertical
+                             ? SuperViewAsScroll.GetContentSize ().Height
+                             : SuperViewAsScroll.GetContentSize ().Width;
 
 
         // Ensure the Position is valid if the slider is at end
         // Ensure the Position is valid if the slider is at end
         // We use Frame here instead of ContentSize because even if the slider has a margin or border, Frame indicates the actual size
         // We use Frame here instead of ContentSize because even if the slider has a margin or border, Frame indicates the actual size
         if ((SuperViewAsScroll.Orientation == Orientation.Vertical && location + Frame.Height >= scrollSize)
         if ((SuperViewAsScroll.Orientation == Orientation.Vertical && location + Frame.Height >= scrollSize)
             || (SuperViewAsScroll.Orientation == Orientation.Horizontal && location + Frame.Width >= scrollSize))
             || (SuperViewAsScroll.Orientation == Orientation.Horizontal && location + Frame.Width >= scrollSize))
         {
         {
-            return SuperViewAsScroll.Size - scrollSize;
+            return SuperViewAsScroll.Size - scrollSize + (SuperViewAsScroll.KeepContentInAllViewport ? 0 : scrollSize);
         }
         }
 
 
         return (int)Math.Min (Math.Round ((double)(location * SuperViewAsScroll.Size + location) / scrollSize), SuperViewAsScroll.Size - scrollSize);
         return (int)Math.Min (Math.Round ((double)(location * SuperViewAsScroll.Size + location) / scrollSize), SuperViewAsScroll.Size - scrollSize);
@@ -164,7 +175,9 @@ internal class ScrollSlider : View
             return new (0, 0);
             return new (0, 0);
         }
         }
 
 
-        int scrollSize = SuperViewAsScroll.Orientation == Orientation.Vertical ? SuperViewAsScroll.GetContentSize ().Height : SuperViewAsScroll.GetContentSize ().Width;
+        int scrollSize = SuperViewAsScroll.Orientation == Orientation.Vertical
+                             ? SuperViewAsScroll.GetContentSize ().Height
+                             : SuperViewAsScroll.GetContentSize ().Width;
         int location;
         int location;
         int dimension;
         int dimension;
 
 
@@ -173,7 +186,8 @@ internal class ScrollSlider : View
             dimension = (int)Math.Min (Math.Max (Math.Ceiling ((double)scrollSize * scrollSize / SuperViewAsScroll.Size), 1), scrollSize);
             dimension = (int)Math.Min (Math.Max (Math.Ceiling ((double)scrollSize * scrollSize / SuperViewAsScroll.Size), 1), scrollSize);
 
 
             // Ensure the Position is valid
             // Ensure the Position is valid
-            if (SuperViewAsScroll.Position > 0 && SuperViewAsScroll.Position + scrollSize > SuperViewAsScroll.Size)
+            if (SuperViewAsScroll.Position > 0
+                && SuperViewAsScroll.Position + scrollSize > SuperViewAsScroll.Size + (SuperViewAsScroll.KeepContentInAllViewport ? 0 : scrollSize))
             {
             {
                 SuperViewAsScroll.Position = SuperViewAsScroll.Size - scrollSize;
                 SuperViewAsScroll.Position = SuperViewAsScroll.Size - scrollSize;
             }
             }

+ 17 - 4
UICatalog/Scenarios/ScrollBarDemo.cs

@@ -182,14 +182,27 @@ public class ScrollBarDemo : Scenario
                                             }
                                             }
                                         };
                                         };
 
 
-        var ckbAutoHideScrollBar = new CheckBox { Y = Pos.Bottom (scrollPosition), Text = "AutoHideScrollBar" };
-        ckbAutoHideScrollBar.CheckedStateChanging += (s, e) => scrollBar.AutoHide = e.NewValue == CheckState.Checked;
-        view.Add (ckbAutoHideScrollBar);
+        var ckbAutoHide = new CheckBox
+            { Y = Pos.Bottom (scrollPosition), Text = "AutoHideScrollBar", CheckedState = scrollBar.AutoHide ? CheckState.Checked : CheckState.UnChecked };
+        ckbAutoHide.CheckedStateChanging += (s, e) => scrollBar.AutoHide = e.NewValue == CheckState.Checked;
+        view.Add (ckbAutoHide);
 
 
-        var ckbShowScrollIndicator = new CheckBox { X = Pos.Right (ckbAutoHideScrollBar) + 1, Y = Pos.Bottom (scrollPosition), Text = "ShowScrollIndicator" };
+        var ckbShowScrollIndicator = new CheckBox
+        {
+            X = Pos.Right (ckbAutoHide) + 1, Y = Pos.Bottom (scrollPosition), Text = "ShowScrollIndicator",
+            CheckedState = scrollBar.ShowScrollIndicator ? CheckState.Checked : CheckState.UnChecked
+        };
         ckbShowScrollIndicator.CheckedStateChanging += (s, e) => scrollBar.ShowScrollIndicator = e.NewValue == CheckState.Checked;
         ckbShowScrollIndicator.CheckedStateChanging += (s, e) => scrollBar.ShowScrollIndicator = e.NewValue == CheckState.Checked;
         view.Add (ckbShowScrollIndicator);
         view.Add (ckbShowScrollIndicator);
 
 
+        var ckbKeepContentInAllViewport = new CheckBox
+        {
+            X = Pos.Right (ckbShowScrollIndicator) + 1, Y = Pos.Bottom (scrollPosition), Text = "KeepContentInAllViewport",
+            CheckedState = scrollBar.KeepContentInAllViewport ? CheckState.Checked : CheckState.UnChecked
+        };
+        ckbKeepContentInAllViewport.CheckedStateChanging += (s, e) => scrollBar.KeepContentInAllViewport = e.NewValue == CheckState.Checked;
+        view.Add (ckbKeepContentInAllViewport);
+
         var lblSizeChanged = new Label
         var lblSizeChanged = new Label
         {
         {
             Y = Pos.Bottom (ckbShowScrollIndicator) + 1
             Y = Pos.Bottom (ckbShowScrollIndicator) + 1

+ 9 - 1
UICatalog/Scenarios/ScrollDemo.cs

@@ -182,9 +182,17 @@ public class ScrollDemo : Scenario
                                             }
                                             }
                                         };
                                         };
 
 
+        var ckbKeepContentInAllViewport = new CheckBox
+        {
+            Y = Pos.Bottom (scrollPosition), Text = "KeepContentInAllViewport",
+            CheckedState = scroll.KeepContentInAllViewport ? CheckState.Checked : CheckState.UnChecked
+        };
+        ckbKeepContentInAllViewport.CheckedStateChanging += (s, e) => scroll.KeepContentInAllViewport = e.NewValue == CheckState.Checked;
+        view.Add (ckbKeepContentInAllViewport);
+
         var lblSizeChanged = new Label
         var lblSizeChanged = new Label
         {
         {
-            Y = Pos.Bottom (lblPosition) + 1
+            Y = Pos.Bottom (ckbKeepContentInAllViewport) + 1
         };
         };
         view.Add (lblSizeChanged);
         view.Add (lblSizeChanged);
 
 

+ 46 - 6
UnitTests/Views/ScrollBarTests.cs

@@ -231,6 +231,37 @@ public class ScrollBarTests
         Assert.True (scrollBar.AutoHide);
         Assert.True (scrollBar.AutoHide);
     }
     }
 
 
+    [Fact]
+    [AutoInitShutdown]
+    public void KeepContentInAllViewport_True_False ()
+    {
+        var view = new View { Width = Dim.Fill (), Height = Dim.Fill () };
+        view.Padding.Thickness = new (0, 0, 2, 0);
+        view.SetContentSize (new (view.Viewport.Width, 30));
+        var scrollBar = new ScrollBar { Width = 2, Height = Dim.Fill (), Size = view.GetContentSize ().Height };
+        scrollBar.PositionChanged += (_, e) => view.Viewport = view.Viewport with { Y = e.CurrentValue };
+        view.Padding.Add (scrollBar);
+        var top = new Toplevel ();
+        top.Add (view);
+        Application.Begin (top);
+
+        Assert.True (scrollBar.KeepContentInAllViewport);
+        Assert.Equal (80, view.Padding.Viewport.Width);
+        Assert.Equal (25, view.Padding.Viewport.Height);
+        Assert.Equal (2, scrollBar.Viewport.Width);
+        Assert.Equal (25, scrollBar.Viewport.Height);
+        Assert.Equal (30, scrollBar.Size);
+
+        scrollBar.KeepContentInAllViewport = false;
+        scrollBar.Position = 50;
+        Assert.Equal (scrollBar.Position, scrollBar.Size - 1);
+        Assert.Equal (scrollBar.Position, view.Viewport.Y);
+        Assert.Equal (29, scrollBar.Position);
+        Assert.Equal (29, view.Viewport.Y);
+
+        top.Dispose ();
+    }
+
     [Theory]
     [Theory]
     [AutoInitShutdown]
     [AutoInitShutdown]
     [InlineData (
     [InlineData (
@@ -848,9 +879,9 @@ public class ScrollBarTests
     }
     }
 
 
     [Theory]
     [Theory]
-    [InlineData (Orientation.Vertical, 20, 10)]
-    [InlineData (Orientation.Vertical, 40, 30)]
-    public void Position_Cannot_Be_Negative_Nor_Greater_Than_Size_Minus_Frame_Length (Orientation orientation, int size, int expectedPos)
+    [InlineData (Orientation.Vertical, 20, 12, 10)]
+    [InlineData (Orientation.Vertical, 40, 32, 30)]
+    public void Position_Cannot_Be_Negative_Nor_Greater_Than_Size_Minus_Frame_Length (Orientation orientation, int size, int expectedPos1, int expectedPos2)
     {
     {
         var scrollBar = new ScrollBar { Orientation = orientation, Height = 10, Size = size };
         var scrollBar = new ScrollBar { Orientation = orientation, Height = 10, Size = size };
         Assert.Equal (0, scrollBar.Position);
         Assert.Equal (0, scrollBar.Position);
@@ -859,10 +890,10 @@ public class ScrollBarTests
         Assert.Equal (0, scrollBar.Position);
         Assert.Equal (0, scrollBar.Position);
 
 
         scrollBar.Position = size;
         scrollBar.Position = size;
-        Assert.Equal (0, scrollBar.Position);
+        Assert.Equal (expectedPos1, scrollBar.Position);
 
 
-        scrollBar.Position = expectedPos;
-        Assert.Equal (expectedPos, scrollBar.Position);
+        scrollBar.Position = expectedPos2;
+        Assert.Equal (expectedPos2, scrollBar.Position);
     }
     }
 
 
     [Fact]
     [Fact]
@@ -1000,6 +1031,15 @@ public class ScrollBarTests
         scrollBarSuperView.SuperView!.Dispose ();
         scrollBarSuperView.SuperView!.Dispose ();
     }
     }
 
 
+    [Fact]
+    public void Size_Cannot_Be_Negative ()
+    {
+        var scrollBar = new ScrollBar { Height = 10, Size = -1 };
+        Assert.Equal (0, scrollBar.Size);
+        scrollBar.Size = -10;
+        Assert.Equal (0, scrollBar.Size);
+    }
+
     [Fact]
     [Fact]
     public void SizeChanged_Event ()
     public void SizeChanged_Event ()
     {
     {

+ 42 - 1
UnitTests/Views/ScrollTests.cs

@@ -190,6 +190,38 @@ public class ScrollTests
         Assert.Equal (Orientation.Vertical, scroll.Orientation);
         Assert.Equal (Orientation.Vertical, scroll.Orientation);
         Assert.Equal (0, scroll.Size);
         Assert.Equal (0, scroll.Size);
         Assert.Equal (0, scroll.Position);
         Assert.Equal (0, scroll.Position);
+        Assert.True (scroll.KeepContentInAllViewport);
+    }
+
+    [Fact]
+    [AutoInitShutdown]
+    public void KeepContentInAllViewport_True_False ()
+    {
+        var view = new View { Width = Dim.Fill (), Height = Dim.Fill () };
+        view.Padding.Thickness = new (0, 0, 2, 0);
+        view.SetContentSize (new (view.Viewport.Width, 30));
+        var scroll = new Scroll { Width = 2, Height = Dim.Fill (), Size = view.GetContentSize ().Height };
+        scroll.PositionChanged += (_, e) => view.Viewport = view.Viewport with { Y = e.CurrentValue };
+        view.Padding.Add (scroll);
+        var top = new Toplevel ();
+        top.Add (view);
+        Application.Begin (top);
+
+        Assert.True (scroll.KeepContentInAllViewport);
+        Assert.Equal (80, view.Padding.Viewport.Width);
+        Assert.Equal (25, view.Padding.Viewport.Height);
+        Assert.Equal (2, scroll.Viewport.Width);
+        Assert.Equal (25, scroll.Viewport.Height);
+        Assert.Equal (30, scroll.Size);
+
+        scroll.KeepContentInAllViewport = false;
+        scroll.Position = 50;
+        Assert.Equal (scroll.Position, scroll.Size - 1);
+        Assert.Equal (scroll.Position, view.Viewport.Y);
+        Assert.Equal (29, scroll.Position);
+        Assert.Equal (29, view.Viewport.Y);
+
+        top.Dispose ();
     }
     }
 
 
     [Theory]
     [Theory]
@@ -759,7 +791,7 @@ public class ScrollTests
         Assert.Equal (0, scroll.Position);
         Assert.Equal (0, scroll.Position);
 
 
         scroll.Position = size;
         scroll.Position = size;
-        Assert.Equal (0, scroll.Position);
+        Assert.Equal (expectedPos, scroll.Position);
 
 
         scroll.Position = expectedPos;
         scroll.Position = expectedPos;
         Assert.Equal (expectedPos, scroll.Position);
         Assert.Equal (expectedPos, scroll.Position);
@@ -864,6 +896,15 @@ public class ScrollTests
         }
         }
     }
     }
 
 
+    [Fact]
+    public void Size_Cannot_Be_Negative ()
+    {
+        var scroll = new Scroll { Height = 10, Size = -1 };
+        Assert.Equal (0, scroll.Size);
+        scroll.Size = -10;
+        Assert.Equal (0, scroll.Size);
+    }
+
     [Fact]
     [Fact]
     public void SizeChanged_Event ()
     public void SizeChanged_Event ()
     {
     {