Przeglądaj źródła

Add scroll bar & slider buttons

Eli Arbel 8 lat temu
rodzic
commit
aee42bad6c

+ 24 - 0
src/Avalonia.Controls/Primitives/RangeBase.cs

@@ -38,6 +38,18 @@ namespace Avalonia.Controls.Primitives
                 o => o.Value,
                 (o, v) => o.Value = v);
 
+        /// <summary>
+        /// Defines the <see cref="SmallChange"/> property.
+        /// </summary>
+        public static readonly StyledProperty<double> SmallChangeProperty =
+            AvaloniaProperty.Register<RangeBase, double>(nameof(SmallChange), 0.1);
+
+        /// <summary>
+        /// Defines the <see cref="LargeChange"/> property.
+        /// </summary>
+        public static readonly StyledProperty<double> LargeChangeProperty =
+            AvaloniaProperty.Register<RangeBase, double>(nameof(LargeChange), 1);
+
         private double _minimum;
         private double _maximum = 100.0;
         private double _value;
@@ -103,6 +115,18 @@ namespace Avalonia.Controls.Primitives
             }
         }
 
+        public double SmallChange
+        {
+            get => GetValue(SmallChangeProperty);
+            set => SetValue(SmallChangeProperty, value);
+        }
+
+        public double LargeChange
+        {
+            get => GetValue(LargeChangeProperty);
+            set => SetValue(LargeChangeProperty, value);
+        }
+
         /// <summary>
         /// Throws an exception if the double valus is NaN or Inf.
         /// </summary>

+ 99 - 4
src/Avalonia.Controls/Primitives/ScrollBar.cs

@@ -5,6 +5,7 @@ using System;
 using System.Reactive;
 using System.Reactive.Linq;
 using Avalonia.Data;
+using Avalonia.Interactivity;
 
 namespace Avalonia.Controls.Primitives
 {
@@ -31,13 +32,18 @@ namespace Avalonia.Controls.Primitives
         public static readonly StyledProperty<Orientation> OrientationProperty =
             AvaloniaProperty.Register<ScrollBar, Orientation>(nameof(Orientation));
 
+        private Button _lineUpButton;
+        private Button _lineDownButton;
+        private Button _pageUpButton;
+        private Button _pageDownButton;
+
         /// <summary>
         /// Initializes static members of the <see cref="ScrollBar"/> class. 
         /// </summary>
         static ScrollBar()
         {
-            PseudoClass(OrientationProperty, o => o == Avalonia.Controls.Orientation.Vertical, ":vertical");
-            PseudoClass(OrientationProperty, o => o == Avalonia.Controls.Orientation.Horizontal, ":horizontal");
+            PseudoClass(OrientationProperty, o => o == Orientation.Vertical, ":vertical");
+            PseudoClass(OrientationProperty, o => o == Orientation.Horizontal, ":horizontal");
         }
 
         /// <summary>
@@ -97,12 +103,101 @@ namespace Avalonia.Controls.Primitives
                     return false;
 
                 case ScrollBarVisibility.Auto:
-                    var viewportSize = ViewportSize;
-                    return double.IsNaN(viewportSize) || viewportSize < Maximum - Minimum;
+                    return double.IsNaN(ViewportSize) || Maximum > 0;
 
                 default:
                     throw new InvalidOperationException("Invalid value for ScrollBar.Visibility.");
             }
         }
+
+        protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
+        {
+            base.OnTemplateApplied(e);
+
+            if (_lineUpButton != null)
+            {
+                _lineUpButton.Click -= LineUpClick;
+            }
+
+            if (_lineDownButton != null)
+            {
+                _lineDownButton.Click -= LineDownClick;
+            }
+
+            if (_pageUpButton != null)
+            {
+                _pageUpButton.Click -= PageUpClick;
+            }
+
+            if (_pageDownButton != null)
+            {
+                _pageDownButton.Click -= PageDownClick;
+            }
+
+            _lineUpButton = e.NameScope.Find<Button>("PART_LineUpButton");
+            _lineDownButton = e.NameScope.Find<Button>("PART_LineDownButton");
+            _pageUpButton = e.NameScope.Find<Button>("PART_PageUpButton");
+            _pageDownButton = e.NameScope.Find<Button>("PART_PageDownButton");
+
+            if (_lineUpButton != null)
+            {
+                _lineUpButton.Click += LineUpClick;
+            }
+
+            if (_lineDownButton != null)
+            {
+                _lineDownButton.Click += LineDownClick;
+            }
+
+            if (_pageUpButton != null)
+            {
+                _pageUpButton.Click += PageUpClick;
+            }
+
+            if (_pageDownButton != null)
+            {
+                _pageDownButton.Click += PageDownClick;
+            }
+        }
+
+        private void LineUpClick(object sender, RoutedEventArgs e)
+        {
+            SmallDecrement();
+        }
+
+        private void LineDownClick(object sender, RoutedEventArgs e)
+        {
+            SmallIncrement();
+        }
+
+        private void PageUpClick(object sender, RoutedEventArgs e)
+        {
+            LargeDecrement();
+        }
+
+        private void PageDownClick(object sender, RoutedEventArgs e)
+        {
+            LargeIncrement();
+        }
+
+        private void SmallDecrement()
+        {
+            Value = Math.Max(Value - SmallChange * ViewportSize, Minimum);
+        }
+
+        private void SmallIncrement()
+        {
+            Value = Math.Min(Value + SmallChange * ViewportSize, Maximum);
+        }
+
+        private void LargeDecrement()
+        {
+            Value = Math.Max(Value - LargeChange * ViewportSize, Minimum);
+        }
+
+        private void LargeIncrement()
+        {
+            Value = Math.Min(Value + LargeChange * ViewportSize, Maximum);
+        }
     }
 }

+ 80 - 22
src/Avalonia.Controls/Primitives/Track.cs

@@ -10,7 +10,7 @@ namespace Avalonia.Controls.Primitives
     public class Track : Control
     {
         public static readonly DirectProperty<Track, double> MinimumProperty =
-            RangeBase.MinimumProperty.AddOwner<Track>(o => o.Minimum, (o,v) => o.Minimum = v);
+            RangeBase.MinimumProperty.AddOwner<Track>(o => o.Minimum, (o, v) => o.Minimum = v);
 
         public static readonly DirectProperty<Track, double> MaximumProperty =
             RangeBase.MaximumProperty.AddOwner<Track>(o => o.Maximum, (o, v) => o.Maximum = v);
@@ -25,7 +25,13 @@ namespace Avalonia.Controls.Primitives
             ScrollBar.OrientationProperty.AddOwner<Track>();
 
         public static readonly StyledProperty<Thumb> ThumbProperty =
-            AvaloniaProperty.Register<Track, Thumb>("Thumb");
+            AvaloniaProperty.Register<Track, Thumb>(nameof(Thumb));
+
+        public static readonly StyledProperty<Button> IncreaseButtonProperty =
+            AvaloniaProperty.Register<Track, Button>(nameof(IncreaseButton));
+
+        public static readonly StyledProperty<Button> DecreaseButtonProperty =
+            AvaloniaProperty.Register<Track, Button>(nameof(DecreaseButton));
 
         private double _minimum;
         private double _maximum = 100.0;
@@ -34,6 +40,8 @@ namespace Avalonia.Controls.Primitives
         static Track()
         {
             ThumbProperty.Changed.AddClassHandler<Track>(x => x.ThumbChanged);
+            IncreaseButtonProperty.Changed.AddClassHandler<Track>(x => x.ButtonChanged);
+            DecreaseButtonProperty.Changed.AddClassHandler<Track>(x => x.ButtonChanged);
             AffectsArrange(MinimumProperty, MaximumProperty, ValueProperty, OrientationProperty);
         }
 
@@ -74,6 +82,18 @@ namespace Avalonia.Controls.Primitives
             set { SetValue(ThumbProperty, value); }
         }
 
+        public Button IncreaseButton
+        {
+            get { return GetValue(IncreaseButtonProperty); }
+            set { SetValue(IncreaseButtonProperty, value); }
+        }
+
+        public Button DecreaseButton
+        {
+            get { return GetValue(DecreaseButtonProperty); }
+            set { SetValue(DecreaseButtonProperty, value); }
+        }
+
         protected override Size MeasureOverride(Size availableSize)
         {
             var thumb = Thumb;
@@ -98,34 +118,54 @@ namespace Avalonia.Controls.Primitives
         protected override Size ArrangeOverride(Size finalSize)
         {
             var thumb = Thumb;
+            var increaseButton = IncreaseButton;
+            var decreaseButton = DecreaseButton;
 
-            if (thumb != null)
+            var range = Maximum - Minimum;
+            var offset = Math.Min(Value - Minimum, range);
+            var viewportSize = ViewportSize;
+            var extent = range + viewportSize;
+
+            if (Orientation == Orientation.Horizontal)
             {
-                var range = Maximum - Minimum;
-                var thumbFraction = ViewportSize / range;
-                var valueFraction = (Value - Minimum) / range;
+                var thumbWidth = double.IsNaN(viewportSize) ? finalSize.Width : finalSize.Width * viewportSize / extent;
+                var remaining = finalSize.Width - thumbWidth;
+                var firstWidth = range <= 0 ? 0 : remaining * offset / range;
 
-                if (double.IsNaN(valueFraction) || double.IsInfinity(valueFraction))
+                if (decreaseButton != null)
                 {
-                    valueFraction = 0;
-                    thumbFraction = 1;
+                    decreaseButton.Arrange(new Rect(0, 0, firstWidth, finalSize.Height));
                 }
-                else if (double.IsNaN(thumbFraction) || double.IsInfinity(thumbFraction))
+
+                if (thumb != null)
                 {
-                    thumbFraction = 0;
+                    thumb.Arrange(new Rect(firstWidth, 0, thumbWidth, finalSize.Height));
                 }
 
-                if (Orientation == Orientation.Horizontal)
+                if (increaseButton != null)
                 {
-                    var width = Math.Max(finalSize.Width * thumbFraction, thumb.MinWidth);
-                    var x = (finalSize.Width - width) * valueFraction;
-                    thumb.Arrange(new Rect(x, 0, width, finalSize.Height));
+                    increaseButton.Arrange(new Rect(firstWidth + thumbWidth, 0, remaining - firstWidth, finalSize.Height));
                 }
-                else
+            }
+            else
+            {
+                var thumbHeight = double.IsNaN(viewportSize) ? finalSize.Height : finalSize.Height * viewportSize / extent;
+                var remaining = finalSize.Height - thumbHeight;
+                var firstHeight = range <= 0 ? 0 : remaining * offset / range;
+
+                if (decreaseButton != null)
                 {
-                    var height = Math.Max(finalSize.Height * thumbFraction, thumb.MinHeight);
-                    var y = (finalSize.Height - height) * valueFraction;
-                    thumb.Arrange(new Rect(0, y, finalSize.Width, height));
+                    decreaseButton.Arrange(new Rect(0, 0, finalSize.Width, firstHeight));
+                }
+
+                if (thumb != null)
+                {
+                    thumb.Arrange(new Rect(0, firstHeight, finalSize.Width, thumbHeight));
+                }
+
+                if (increaseButton != null)
+                {
+                    increaseButton.Arrange(new Rect(0, firstHeight + thumbHeight, finalSize.Width, remaining - firstHeight));
                 }
             }
 
@@ -140,10 +180,10 @@ namespace Avalonia.Controls.Primitives
             if (oldThumb != null)
             {
                 oldThumb.DragDelta -= ThumbDragged;
-            }
 
-            LogicalChildren.Clear();
-            VisualChildren.Clear();
+                LogicalChildren.Remove(oldThumb);
+                VisualChildren.Remove(oldThumb);
+            }
 
             if (newThumb != null)
             {
@@ -153,6 +193,24 @@ namespace Avalonia.Controls.Primitives
             }
         }
 
+        private void ButtonChanged(AvaloniaPropertyChangedEventArgs e)
+        {
+            var oldButton = (Button)e.OldValue;
+            var newButton = (Button)e.NewValue;
+
+            if (oldButton != null)
+            {
+                LogicalChildren.Remove(oldButton);
+                VisualChildren.Remove(oldButton);
+            }
+
+            if (newButton != null)
+            {
+                LogicalChildren.Add(newButton);
+                VisualChildren.Add(newButton);
+            }
+        }
+
         private void ThumbDragged(object sender, VectorEventArgs e)
         {
             double range = Maximum - Minimum;

+ 2 - 2
src/Avalonia.Controls/ScrollViewer.cs

@@ -275,7 +275,7 @@ namespace Avalonia.Controls
         /// </summary>
         protected double HorizontalScrollBarViewportSize
         {
-            get { return Max((_viewport.Width / _extent.Width) * (_extent.Width - _viewport.Width), 0); }
+            get { return _viewport.Width; }
         }
 
         /// <summary>
@@ -308,7 +308,7 @@ namespace Avalonia.Controls
         /// </summary>
         protected double VerticalScrollBarViewportSize
         {
-            get { return Max((_viewport.Height / _extent.Height) * (_extent.Height - _viewport.Height), 0); }
+            get { return _viewport.Height; }
         }
 
         /// <summary>

+ 36 - 2
src/Avalonia.Controls/Slider.cs

@@ -33,6 +33,8 @@ namespace Avalonia.Controls
 
         // Slider required parts
         private Track _track;
+        private Button _decreaseButton;
+        private Button _increaseButton;
 
         /// <summary>
         /// Initializes static members of the <see cref="Slider"/> class. 
@@ -83,7 +85,39 @@ namespace Avalonia.Controls
         /// <inheritdoc/>
         protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
         {
-            _track = e.NameScope.Get<Track>("PART_Track");
+            if (_decreaseButton != null)
+            {
+                _decreaseButton.Click -= DecreaseClick;
+            }
+
+            if (_increaseButton != null)
+            {
+                _increaseButton.Click -= IncreaseClick;
+            }
+
+            _decreaseButton = e.NameScope.Find<Button>("PART_DecreaseButton");
+            _track = e.NameScope.Find<Track>("PART_Track");
+            _increaseButton = e.NameScope.Find<Button>("PART_IncreaseButton");
+
+            if (_decreaseButton != null)
+            {
+                _decreaseButton.Click += DecreaseClick;
+            }
+
+            if (_increaseButton != null)
+            {
+                _increaseButton.Click += IncreaseClick;
+            }
+        }
+
+        private void DecreaseClick(object sender, RoutedEventArgs e)
+        {
+            Value = Math.Max(Value - LargeChange, Minimum);
+        }
+
+        private void IncreaseClick(object sender, RoutedEventArgs e)
+        {
+            Value = Math.Min(Value + LargeChange, Maximum);
         }
 
         /// <summary>
@@ -101,7 +135,7 @@ namespace Avalonia.Controls
         protected virtual void OnThumbDragDelta(VectorEventArgs e)
         {
             Thumb thumb = e.Source as Thumb;
-            if (thumb != null && _track.Thumb == thumb)
+            if (thumb != null && _track?.Thumb == thumb)
             {
                 MoveToNextTick(_track.Value);
             }

+ 125 - 33
src/Avalonia.Themes.Default/ScrollBar.xaml

@@ -1,35 +1,127 @@
 <Styles xmlns="https://github.com/avaloniaui">
-  <Style Selector="ScrollBar">
-    <Setter Property="Template">
-      <ControlTemplate>
-        <Border Background="{StyleResource ThemeControlMidBrush}">
-          <Track Minimum="{TemplateBinding Minimum}"
-                 Maximum="{TemplateBinding Maximum}"
-                 Value="{TemplateBinding Path=Value, Mode=TwoWay}"
-                 ViewportSize="{TemplateBinding ViewportSize}"
-                 Orientation="{TemplateBinding Orientation}">
-            <Thumb Name="thumb">
-              <Thumb.Template>
-                <ControlTemplate>
-                  <Border Background="{StyleResource ThemeControlDarkBrush}"/>
-                </ControlTemplate>
-              </Thumb.Template>
-            </Thumb>
-          </Track>
-        </Border>
-      </ControlTemplate>
-    </Setter>
-  </Style>
-  <Style Selector="ScrollBar:horizontal">
-    <Setter Property="Height" Value="10"/>
-  </Style>
-  <Style Selector="ScrollBar:horizontal /template/ Thumb#thumb">
-    <Setter Property="MinWidth" Value="10"/>
-  </Style>
-  <Style Selector="ScrollBar:vertical">
-    <Setter Property="Width" Value="10"/>
-  </Style>
-  <Style Selector="ScrollBar:vertical /template/ Thumb#thumb">
-    <Setter Property="MinHeight" Value="10"/>
-  </Style>
+    <Style Selector="ScrollBar">
+        <Setter Property="Template">
+            <ControlTemplate>
+                <Border Background="{StyleResource ThemeControlMidBrush}">
+                    <Grid RowDefinitions="10,*,10">
+                        <RepeatButton Name="PART_LineUpButton"
+                                      Classes="repeat"
+                                      Grid.Row="0"
+                                      Grid.Column="0">
+                            <Path Data="M 0,4 C0,4 0,6 0,6 0,6 3.5,2.5 3.5,2.5 3.5,2.5 7,6 7,6 7,6 7,4 7,4 7,4 3.5,0.5 3.5,0.5 3.5,0.5 0,4 0,4 z"
+                                  Stretch="Uniform"
+                                  Fill="Gray" />
+                        </RepeatButton>
+                        <Track Grid.Row="1"
+                               Grid.Column="1"
+                               Minimum="{TemplateBinding Minimum}"
+                               Maximum="{TemplateBinding Maximum}"
+                               Value="{TemplateBinding Path=Value, Mode=TwoWay}"
+                               ViewportSize="{TemplateBinding ViewportSize}"
+                               Orientation="{TemplateBinding Orientation}">
+                            <Track.DecreaseButton>
+                                <RepeatButton Name="PART_PageUpButton"
+                                              Classes="repeattrack" />
+                            </Track.DecreaseButton>
+                            <Track.IncreaseButton>
+                                <RepeatButton Name="PART_PageDownButton"
+                                              Classes="repeattrack" />
+                            </Track.IncreaseButton>
+                            <Thumb Name="thumb">
+                                <Thumb.Template>
+                                    <ControlTemplate>
+                                        <Border Background="{StyleResource ThemeControlDarkBrush}" />
+                                    </ControlTemplate>
+                                </Thumb.Template>
+                            </Thumb>
+                        </Track>
+                        <RepeatButton Name="PART_LineDownButton"
+                                      Classes="repeat"
+                                      Grid.Row="2"
+                                      Grid.Column="2">
+                            <Path Data="M 0,2.5 C0,2.5 0,0.5 0,0.5 0,0.5 3.5,4 3.5,4 3.5,4 7,0.5 7,0.5 7,0.5 7,2.5 7,2.5 7,2.5 3.5,6 3.5,6 3.5,6 0,2.5 0,2.5 z"
+                                  Stretch="Uniform"
+                                  Fill="Gray" />
+                        </RepeatButton>
+                    </Grid>
+                </Border>
+            </ControlTemplate>
+        </Setter>
+    </Style>
+    <Style Selector="ScrollBar:horizontal">
+        <Setter Property="Height"
+                Value="10" />
+        <Setter Property="Template">
+            <ControlTemplate>
+                <Border Background="{StyleResource ThemeControlMidBrush}">
+                    <Grid ColumnDefinitions="10,*,10">
+                        <RepeatButton Name="PART_LineUpButton"
+                                      Classes="repeat"
+                                      Grid.Row="0"
+                                      Grid.Column="0">
+                            <Path Data="M 3.18,7 C3.18,7 5,7 5,7 5,7 1.81,3.5 1.81,3.5 1.81,3.5 5,0 5,0 5,0 3.18,0 3.18,0 3.18,0 0,3.5 0,3.5 0,3.5 3.18,7 3.18,7 z"
+                                  Stretch="Uniform"
+                                  Fill="Gray" />
+                        </RepeatButton>
+                        <Track Grid.Row="1"
+                               Grid.Column="1"
+                               Minimum="{TemplateBinding Minimum}"
+                               Maximum="{TemplateBinding Maximum}"
+                               Value="{TemplateBinding Path=Value, Mode=TwoWay}"
+                               ViewportSize="{TemplateBinding ViewportSize}"
+                               Orientation="{TemplateBinding Orientation}">
+                            <Track.DecreaseButton>
+                                <RepeatButton Name="PART_PageUpButton"
+                                              Classes="repeattrack" />
+                            </Track.DecreaseButton>
+                            <Track.IncreaseButton>
+                                <RepeatButton Name="PART_PageDownButton"
+                                              Classes="repeattrack" />
+                            </Track.IncreaseButton>
+                            <Thumb Name="thumb">
+                                <Thumb.Template>
+                                    <ControlTemplate>
+                                        <Border Background="{StyleResource ThemeControlDarkBrush}" />
+                                    </ControlTemplate>
+                                </Thumb.Template>
+                            </Thumb>
+                        </Track>
+                        <RepeatButton Name="PART_LineDownButton"
+                                      Classes="repeat"
+                                      Grid.Row="2"
+                                      Grid.Column="2">
+                            <Path Data="M 1.81,7 C1.81,7 0,7 0,7 0,7 3.18,3.5 3.18,3.5 3.18,3.5 0,0 0,0 0,0 1.81,0 1.81,0 1.81,0 5,3.5 5,3.5 5,3.5 1.81,7 1.81,7 z"
+                                  Stretch="Uniform"
+                                  Fill="Gray" />
+                        </RepeatButton>
+                    </Grid>
+                </Border>
+            </ControlTemplate>
+        </Setter>
+    </Style>
+    <Style Selector="ScrollBar:horizontal /template/ Thumb#thumb">
+        <Setter Property="MinWidth"
+                Value="10" />
+    </Style>
+    <Style Selector="ScrollBar:vertical">
+        <Setter Property="Width"
+                Value="10" />
+    </Style>
+    <Style Selector="ScrollBar:vertical /template/ Thumb#thumb">
+        <Setter Property="MinHeight"
+                Value="10" />
+    </Style>
+    <Style Selector="ScrollBar /template/ RepeatButton.repeat">
+        <Setter Property="Padding"
+                Value="2" />
+        <Setter Property="BorderThickness"
+                Value="0" />
+    </Style>
+    <Style Selector="ScrollBar /template/ RepeatButton.repeattrack">
+        <Setter Property="Template">
+            <ControlTemplate>
+                <Border Background="{TemplateBinding Background}" />
+            </ControlTemplate>
+        </Setter>
+    </Style>
 </Styles>

+ 2 - 0
src/Avalonia.Themes.Default/ScrollViewer.xaml

@@ -1,4 +1,6 @@
 <Style xmlns="https://github.com/avaloniaui" Selector="ScrollViewer">
+  <Setter Property="Background"
+          Value="Transparent" />
   <Setter Property="Template">
     <ControlTemplate>
       <Grid ColumnDefinitions="*,Auto" RowDefinitions="*,Auto">

+ 25 - 1
src/Avalonia.Themes.Default/Slider.xaml

@@ -12,6 +12,14 @@
           </Grid.RowDefinitions>
           <Border Name="TrackBackground" Grid.Row="1" Height="4" Margin="6,0" VerticalAlignment="Center"/>
           <Track Name="PART_Track" Grid.Row="1">
+            <Track.DecreaseButton>
+               <RepeatButton Name="PART_DecreaseButton"
+                             Classes="repeattrack" />
+            </Track.DecreaseButton>
+            <Track.IncreaseButton>
+               <RepeatButton Name="PART_IncreaseButton"
+                             Classes="repeattrack" />
+            </Track.IncreaseButton>
             <Thumb MinWidth="20" MinHeight="20">
               <Thumb.Template>
                 <ControlTemplate>
@@ -39,6 +47,14 @@
           </Grid.ColumnDefinitions>
           <Border Name="TrackBackground" Grid.Column="1" Width="4" Margin="0,6" HorizontalAlignment="Center"/>
           <Track Name="PART_Track" Grid.Column="1">
+            <Track.DecreaseButton>
+               <RepeatButton Name="PART_DecreaseButton"
+                             Classes="repeattrack" />
+            </Track.DecreaseButton>
+            <Track.IncreaseButton>
+               <RepeatButton Name="PART_IncreaseButton"
+                             Classes="repeattrack" />
+            </Track.IncreaseButton>
             <Thumb MinWidth="20" MinHeight="20">
               <Thumb.Template>
                 <ControlTemplate>
@@ -62,5 +78,13 @@
   <Style Selector="Slider /template/ Border#TrackBackground">
     <Setter Property="BorderThickness" Value="2"/>
     <Setter Property="BorderBrush" Value="{StyleResource ThemeBorderLightBrush}"/>
-  </Style>  
+  </Style>
+  <Style Selector="Slider /template/ RepeatButton.repeattrack">
+    <Setter Property="Background" Value="Transparent"/>
+    <Setter Property="Template">
+        <ControlTemplate>
+            <Border Background="{TemplateBinding Background}" />
+        </ControlTemplate>
+    </Setter>
+  </Style>
 </Styles>

+ 2 - 3
tests/Avalonia.Controls.UnitTests/Primitives/ScrollBarTests.cs

@@ -65,9 +65,8 @@ namespace Avalonia.Controls.UnitTests.Primitives
             var target = new ScrollBar();
 
             target.Visibility = ScrollBarVisibility.Auto;
-            target.Minimum = 0;
-            target.Maximum = 100;
-            target.ViewportSize = 100;
+            target.ViewportSize = 1;
+            target.Maximum = 0;
 
             Assert.False(target.IsVisible);
         }

+ 3 - 3
tests/Avalonia.Controls.UnitTests/Primitives/TrackTests.cs

@@ -69,7 +69,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
             target.Measure(new Size(100, 100));
             target.Arrange(new Rect(0, 0, 100, 100));
 
-            Assert.Equal(new Rect(25, 0, 50, 12), thumb.Bounds);
+            Assert.Equal(new Rect(33, 0, 34, 12), thumb.Bounds);
         }
 
         [Fact]
@@ -85,7 +85,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 Thumb = thumb,
                 Orientation = Orientation.Vertical,
                 Minimum = 100,
-                Maximum = 300,
+                Maximum = 200,
                 Value = 150,
                 ViewportSize = 50,
                 Width = 12,
@@ -94,7 +94,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
             target.Measure(new Size(100, 100));
             target.Arrange(new Rect(0, 0, 100, 100));
 
-            Assert.Equal(new Rect(0, 18, 12, 25), thumb.Bounds);
+            Assert.Equal(new Rect(0, 33, 12, 34), thumb.Bounds);
         }
 
         [Fact]

+ 9 - 0
tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs

@@ -173,6 +173,15 @@ namespace Avalonia.Layout.UnitTests
                     It.IsAny<IReadOnlyList<FormattedTextStyleSpan>>()))
                 .Returns(new FormattedTextMock("TEST"));
 
+            var streamGeometry = new Mock<IStreamGeometryImpl>();
+            streamGeometry.Setup(x =>
+                    x.Open())
+                .Returns(new Mock<IStreamGeometryContextImpl>().Object);
+
+            renderInterface.Setup(x =>
+                    x.CreateStreamGeometry())
+                .Returns(streamGeometry.Object);
+
             var windowImpl = new Mock<IWindowImpl>();
 
             Size clientSize = default(Size);