@ -16,54 +16,25 @@ namespace Avalonia.Controls
[TemplatePart("PART_VerticalScrollBar", typeof(ScrollBar))]
public class ScrollViewer : ContentControl , IScrollable , IScrollAnchorProvider
{
/// <summary>
/// Defines the <see cref="CanHorizontallyScroll"/> property.
/// </summary>
/// <remarks>
/// There is no public C# accessor for this property as it is intended to be bound to by a
/// <see cref="ScrollContentPresenter"/> in the control's template.
/// </remarks>
public static readonly DirectProperty < ScrollViewer , bool > CanHorizontallyScrollProperty =
AvaloniaProperty . RegisterDirect < ScrollViewer , bool > (
nameof ( CanHorizontallyScroll ) ,
o = > o . CanHorizontallyScroll ) ;
/// <summary>
/// Defines the <see cref="CanVerticallyScroll"/> property.
/// </summary>
/// <remarks>
/// There is no public C# accessor for this property as it is intended to be bound to by a
/// <see cref="ScrollContentPresenter"/> in the control's template.
/// </remarks>
public static readonly DirectProperty < ScrollViewer , bool > CanVerticallyScrollProperty =
AvaloniaProperty . RegisterDirect < ScrollViewer , bool > (
nameof ( CanVerticallyScroll ) ,
o = > o . CanVerticallyScroll ) ;
/// <summary>
/// Defines the <see cref="Extent"/> property.
/// </summary>
public static readonly DirectProperty < ScrollViewer , Size > ExtentProperty =
AvaloniaProperty . RegisterDirect < ScrollViewer , Size > ( nameof ( Extent ) ,
o = > o . Extent ,
( o , v ) = > o . Extent = v ) ;
o = > o . Extent ) ;
/// <summary>
/// Defines the <see cref="Offset"/> property.
/// </summary>
public static readonly DirectProperty < ScrollViewer , Vector > OffsetProperty =
AvaloniaProperty . RegisterDirect < ScrollViewer , Vector > (
nameof ( Offset ) ,
o = > o . Offset ,
( o , v ) = > o . Offset = v ) ;
public static readonly StyledProperty < Vector > OffsetProperty =
AvaloniaProperty . Register < ScrollViewer , Vector > ( nameof ( Offset ) , coerce : CoerceOffset ) ;
/// <summary>
/// Defines the <see cref="Viewport"/> property.
/// </summary>
public static readonly DirectProperty < ScrollViewer , Size > ViewportProperty =
AvaloniaProperty . RegisterDirect < ScrollViewer , Size > ( nameof ( Viewport ) ,
o = > o . Viewport ,
( o , v ) = > o . Viewport = v ) ;
o = > o . Viewport ) ;
/// <summary>
/// Defines the <see cref="LargeChange"/> property.
@ -82,41 +53,12 @@ namespace Avalonia.Controls
o = > o . SmallChange ) ;
/// <summary>
/// Defines the HorizontalScrollBarMaximum property.
/// </summary>
/// <remarks>
/// There is no public C# accessor for this property as it is intended to be bound to by a
/// <see cref="ScrollContentPresenter"/> in the control's template.
/// </remarks>
public static readonly DirectProperty < ScrollViewer , double > HorizontalScrollBarMaximumProperty =
AvaloniaProperty . RegisterDirect < ScrollViewer , double > (
nameof ( HorizontalScrollBarMaximum ) ,
o = > o . HorizontalScrollBarMaximum ) ;
/// <summary>
/// Defines the HorizontalScrollBarValue property.
/// Defines the <see cref="ScrollBarMaximum"/> property.
/// </summary>
/// <remarks>
/// There is no public C# accessor for this property as it is intended to be bound to by a
/// <see cref="ScrollContentPresenter"/> in the control's template.
/// </remarks>
public static readonly DirectProperty < ScrollViewer , double > HorizontalScrollBarValueProperty =
AvaloniaProperty . RegisterDirect < ScrollViewer , double > (
nameof ( HorizontalScrollBarValue ) ,
o = > o . HorizontalScrollBarValue ,
( o , v ) = > o . HorizontalScrollBarValue = v ) ;
/// <summary>
/// Defines the HorizontalScrollBarViewportSize property.
/// </summary>
/// <remarks>
/// There is no public C# accessor for this property as it is intended to be bound to by a
/// <see cref="ScrollContentPresenter"/> in the control's template.
/// </remarks>
public static readonly DirectProperty < ScrollViewer , double > HorizontalScrollBarViewportSizeProperty =
AvaloniaProperty . RegisterDirect < ScrollViewer , double > (
nameof ( HorizontalScrollBarViewportSize ) ,
o = > o . HorizontalScrollBarViewportSize ) ;
public static readonly DirectProperty < ScrollViewer , Vector > ScrollBarMaximumProperty =
AvaloniaProperty . RegisterDirect < ScrollViewer , Vector > (
nameof ( ScrollBarMaximum ) ,
o = > o . ScrollBarMaximum ) ;
/// <summary>
/// Defines the <see cref="HorizontalScrollBarVisibility"/> property.
@ -126,31 +68,6 @@ namespace Avalonia.Controls
nameof ( HorizontalScrollBarVisibility ) ,
ScrollBarVisibility . Disabled ) ;
/// <summary>
/// Defines the VerticalScrollBarMaximum property.
/// </summary>
/// <remarks>
/// There is no public C# accessor for this property as it is intended to be bound to by a
/// <see cref="ScrollContentPresenter"/> in the control's template.
/// </remarks>
public static readonly DirectProperty < ScrollViewer , double > VerticalScrollBarMaximumProperty =
AvaloniaProperty . RegisterDirect < ScrollViewer , double > (
nameof ( VerticalScrollBarMaximum ) ,
o = > o . VerticalScrollBarMaximum ) ;
/// <summary>
/// Defines the VerticalScrollBarValue property.
/// </summary>
/// <remarks>
/// There is no public C# accessor for this property as it is intended to be bound to by a
/// <see cref="ScrollContentPresenter"/> in the control's template.
/// </remarks>
public static readonly DirectProperty < ScrollViewer , double > VerticalScrollBarValueProperty =
AvaloniaProperty . RegisterDirect < ScrollViewer , double > (
nameof ( VerticalScrollBarValue ) ,
o = > o . VerticalScrollBarValue ,
( o , v ) = > o . VerticalScrollBarValue = v ) ;
/// <summary>
/// Defines the <see cref="HorizontalSnapPointsType"/> property.
/// </summary>
@ -179,18 +96,6 @@ namespace Avalonia.Controls
AvaloniaProperty . RegisterAttached < ScrollViewer , Control , SnapPointsAlignment > (
nameof ( VerticalSnapPointsAlignment ) ) ;
/// <summary>
/// Defines the VerticalScrollBarViewportSize property.
/// </summary>
/// <remarks>
/// There is no public C# accessor for this property as it is intended to be bound to by a
/// <see cref="ScrollContentPresenter"/> in the control's template.
/// </remarks>
public static readonly DirectProperty < ScrollViewer , double > VerticalScrollBarViewportSizeProperty =
AvaloniaProperty . RegisterDirect < ScrollViewer , double > (
nameof ( VerticalScrollBarViewportSize ) ,
o = > o . VerticalScrollBarViewportSize ) ;
/// <summary>
/// Defines the <see cref="VerticalScrollBarVisibility"/> property.
/// </summary>
@ -242,25 +147,16 @@ namespace Avalonia.Controls
private IDisposable ? _ childSubscription ;
private ILogicalScrollable ? _l ogicalScrollable ;
private Size _ extent ;
private Vector _ offset ;
private Size _ viewport ;
private Size _ oldExtent ;
private Vector _ oldOffset ;
private Vector _ oldMaximum ;
private Size _ oldViewport ;
private Size _l argeChange ;
private Size _ smallChange = new Size ( DefaultSmallChange , DefaultSmallChange ) ;
private bool _ isExpanded ;
private IDisposable ? _ scrollBarExpandSubscription ;
/// <summary>
/// Initializes static members of the <see cref="ScrollViewer"/> class.
/// </summary>
static ScrollViewer ( )
{
HorizontalScrollBarVisibilityProperty . Changed . AddClassHandler < ScrollViewer , ScrollBarVisibility > ( ( x , e ) = > x . ScrollBarVisibilityChanged ( e ) ) ;
VerticalScrollBarVisibilityProperty . Changed . AddClassHandler < ScrollViewer , ScrollBarVisibility > ( ( x , e ) = > x . ScrollBarVisibilityChanged ( e ) ) ;
}
/// <summary>
/// Initializes a new instance of the <see cref="ScrollViewer"/> class.
/// </summary>
@ -288,7 +184,7 @@ namespace Avalonia.Controls
return _ extent ;
}
private set
internal set
{
if ( SetAndRaise ( ExtentProperty , ref _ extent , value ) )
{
@ -302,18 +198,8 @@ namespace Avalonia.Controls
/// </summary>
public Vector Offset
{
get
{
return _ offset ;
}
set
{
if ( SetAndRaise ( OffsetProperty , ref _ offset , CoerceOffset ( Extent , Viewport , value ) ) )
{
CalculatedPropertiesChanged ( ) ;
}
}
get = > GetValue ( OffsetProperty ) ;
set = > SetValue ( OffsetProperty , value ) ;
}
/// <summary>
@ -326,7 +212,7 @@ namespace Avalonia.Controls
return _ viewport ;
}
private set
internal set
{
if ( SetAndRaise ( ViewportProperty , ref _ viewport , value ) )
{
@ -383,70 +269,9 @@ namespace Avalonia.Controls
public Control ? CurrentAnchor = > ( Presenter as IScrollAnchorProvider ) ? . CurrentAnchor ;
/// <summary>
/// Gets the maximum horizontal scrollbar value .
/// Gets the maximum scrolling distance (which is <see cref="Extent"/> - <see cref="Viewport"/>) .
/// </summary>
protected double HorizontalScrollBarMaximum
{
get { return Max ( _ extent . Width - _ viewport . Width , 0 ) ; }
}
/// <summary>
/// Gets or sets the horizontal scrollbar value.
/// </summary>
protected double HorizontalScrollBarValue
{
get { return _ offset . X ; }
set
{
if ( _ offset . X ! = value )
{
var old = Offset . X ;
Offset = Offset . WithX ( value ) ;
RaisePropertyChanged ( HorizontalScrollBarValueProperty , old , value ) ;
}
}
}
/// <summary>
/// Gets the size of the horizontal scrollbar viewport.
/// </summary>
protected double HorizontalScrollBarViewportSize
{
get { return _ viewport . Width ; }
}
/// <summary>
/// Gets the maximum vertical scrollbar value.
/// </summary>
protected double VerticalScrollBarMaximum
{
get { return Max ( _ extent . Height - _ viewport . Height , 0 ) ; }
}
/// <summary>
/// Gets or sets the vertical scrollbar value.
/// </summary>
protected double VerticalScrollBarValue
{
get { return _ offset . Y ; }
set
{
if ( _ offset . Y ! = value )
{
var old = Offset . Y ;
Offset = Offset . WithY ( value ) ;
RaisePropertyChanged ( VerticalScrollBarValueProperty , old , value ) ;
}
}
}
/// <summary>
/// Gets the size of the vertical scrollbar viewport.
/// </summary>
protected double VerticalScrollBarViewportSize
{
get { return _ viewport . Height ; }
}
public Vector ScrollBarMaximum = > new ( Max ( _ extent . Width - _ viewport . Width , 0 ) , Max ( _ extent . Height - _ viewport . Height , 0 ) ) ;
/// <summary>
/// Gets a value that indicates whether any scrollbar is expanded.
@ -528,82 +353,52 @@ namespace Avalonia.Controls
/// <summary>
/// Scrolls the content up one line.
/// </summary>
public void LineUp ( )
{
Offset - = new Vector ( 0 , _ smallChange . Height ) ;
}
public void LineUp ( ) = > SetCurrentValue ( OffsetProperty , Offset - new Vector ( 0 , _ smallChange . Height ) ) ;
/// <summary>
/// Scrolls the content down one line.
/// </summary>
public void LineDown ( )
{
Offset + = new Vector ( 0 , _ smallChange . Height ) ;
}
public void LineDown ( ) = > SetCurrentValue ( OffsetProperty , Offset + new Vector ( 0 , _ smallChange . Height ) ) ;
/// <summary>
/// Scrolls the content left one line.
/// </summary>
public void LineLeft ( )
{
Offset - = new Vector ( _ smallChange . Width , 0 ) ;
}
public void LineLeft ( ) = > SetCurrentValue ( OffsetProperty , Offset - new Vector ( _ smallChange . Width , 0 ) ) ;
/// <summary>
/// Scrolls the content right one line.
/// </summary>
public void LineRight ( )
{
Offset + = new Vector ( _ smallChange . Width , 0 ) ;
}
public void LineRight ( ) = > SetCurrentValue ( OffsetProperty , Offset + new Vector ( _ smallChange . Width , 0 ) ) ;
/// <summary>
/// Scrolls the content upward by one page.
/// </summary>
public void PageUp ( )
{
VerticalScrollBarValue = Math . Max ( _ offset . Y - _ viewport . Height , 0 ) ;
}
public void PageUp ( ) = > SetCurrentValue ( OffsetProperty , Offset . WithY ( Math . Max ( Offset . Y - _ viewport . Height , 0 ) ) ) ;
/// <summary>
/// Scrolls the content downward by one page.
/// </summary>
public void PageDown ( )
{
VerticalScrollBarValue = Math . Min ( _ offset . Y + _ viewport . Height , VerticalScrollBarMaximum ) ;
}
public void PageDown ( ) = > SetCurrentValue ( OffsetProperty , Offset . WithY ( Math . Min ( Offset . Y + _ viewport . Height , ScrollBarMaximum . Y ) ) ) ;
/// <summary>
/// Scrolls the content left by one page.
/// </summary>
public void PageLeft ( )
{
HorizontalScrollBarValue = Math . Max ( _ offset . X - _ viewport . Width , 0 ) ;
}
public void PageLeft ( ) = > SetCurrentValue ( OffsetProperty , Offset . WithX ( Math . Max ( Offset . X - _ viewport . Width , 0 ) ) ) ;
/// <summary>
/// Scrolls the content tight by one page.
/// </summary>
public void PageRight ( )
{
HorizontalScrollBarValue = Math . Min ( _ offset . X + _ viewport . Width , HorizontalScrollBarMaximum ) ;
}
public void PageRight ( ) = > SetCurrentValue ( OffsetProperty , Offset . WithX ( Math . Min ( Offset . X + _ viewport . Width , ScrollBarMaximum . X ) ) ) ;
/// <summary>
/// Scrolls to the top-left corner of the content.
/// </summary>
public void ScrollToHome ( )
{
Offset = new Vector ( double . NegativeInfinity , double . NegativeInfinity ) ;
}
public void ScrollToHome ( ) = > SetCurrentValue ( OffsetProperty , new Vector ( double . NegativeInfinity , double . NegativeInfinity ) ) ;
/// <summary>
/// Scrolls to the bottom-left corner of the content.
/// </summary>
public void ScrollToEnd ( )
{
Offset = new Vector ( double . NegativeInfinity , double . PositiveInfinity ) ;
}
public void ScrollToEnd ( ) = > SetCurrentValue ( OffsetProperty , new Vector ( double . NegativeInfinity , double . PositiveInfinity ) ) ;
/// <summary>
/// Gets the value of the HorizontalScrollBarVisibility attached property.
@ -819,11 +614,14 @@ namespace Avalonia.Controls
return false ;
}
internal static Vector CoerceOffset ( Size extent , Size viewport , Vector offset )
internal static Vector CoerceOffset ( AvaloniaObject sender , Vector value )
{
var extent = sender . GetValue ( ExtentProperty ) ;
var viewport = sender . GetValue ( ViewportProperty ) ;
var maxX = Math . Max ( extent . Width - viewport . Width , 0 ) ;
var maxY = Math . Max ( extent . Height - viewport . Height , 0 ) ;
return new Vector ( Clamp ( offset . X , 0 , maxX ) , Clamp ( offset . Y , 0 , maxY ) ) ;
return new Vector ( Clamp ( value . X , 0 , maxX ) , Clamp ( value . Y , 0 , maxY ) ) ;
}
private static double Clamp ( double value , double min , double max )
@ -859,40 +657,11 @@ namespace Avalonia.Controls
CalculatedPropertiesChanged ( ) ;
}
private void ScrollBarVisibilityChanged ( AvaloniaPropertyChangedEventArgs < ScrollBarVisibility > e )
{
var wasEnabled = e . OldValue . GetValueOrDefault ( ) ! = ScrollBarVisibility . Disabled ;
var isEnabled = e . NewValue . GetValueOrDefault ( ) ! = ScrollBarVisibility . Disabled ;
if ( wasEnabled ! = isEnabled )
{
if ( e . Property = = HorizontalScrollBarVisibilityProperty )
{
RaisePropertyChanged (
CanHorizontallyScrollProperty ,
wasEnabled ,
isEnabled ) ;
}
else if ( e . Property = = VerticalScrollBarVisibilityProperty )
{
RaisePropertyChanged (
CanVerticallyScrollProperty ,
wasEnabled ,
isEnabled ) ;
}
}
}
private void CalculatedPropertiesChanged ( )
{
// Pass old values of 0 here because we don't have the old values at this point,
// and it shouldn't matter as only the template uses these properties.
RaisePropertyChanged ( HorizontalScrollBarMaximumProperty , 0 , HorizontalScrollBarMaximum ) ;
RaisePropertyChanged ( HorizontalScrollBarValueProperty , 0 , HorizontalScrollBarValue ) ;
RaisePropertyChanged ( HorizontalScrollBarViewportSizeProperty , 0 , HorizontalScrollBarViewportSize ) ;
RaisePropertyChanged ( VerticalScrollBarMaximumProperty , 0 , VerticalScrollBarMaximum ) ;
RaisePropertyChanged ( VerticalScrollBarValueProperty , 0 , VerticalScrollBarValue ) ;
RaisePropertyChanged ( VerticalScrollBarViewportSizeProperty , 0 , VerticalScrollBarViewportSize ) ;
var newMaximum = ScrollBarMaximum ;
RaisePropertyChanged ( ScrollBarMaximumProperty , _ oldMaximum , newMaximum ) ;
_ oldMaximum = newMaximum ;
if ( _l ogicalScrollable ? . IsLogicalScrollEnabled = = true )
{
@ -906,6 +675,16 @@ namespace Avalonia.Controls
}
}
protected override void OnPropertyChanged ( AvaloniaPropertyChangedEventArgs change )
{
base . OnPropertyChanged ( change ) ;
if ( change . Property = = OffsetProperty )
{
CalculatedPropertiesChanged ( ) ;
}
}
protected override void OnKeyDown ( KeyEventArgs e )
{
if ( e . Key = = Key . PageUp )