From 46b3ce2a01489455b4a25a0010c70fc6f5c0ab17 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 10 Mar 2016 00:00:26 +0100 Subject: [PATCH] Fix ScrollViewer. Use calculated values for scrollbar properties where possible. --- src/Perspex.Base/PerspexObject.cs | 2 +- src/Perspex.Controls/ScrollViewer.cs | 180 +++++++++++++++++++-------- 2 files changed, 129 insertions(+), 53 deletions(-) diff --git a/src/Perspex.Base/PerspexObject.cs b/src/Perspex.Base/PerspexObject.cs index f35bb21b3fe..53354102227 100644 --- a/src/Perspex.Base/PerspexObject.cs +++ b/src/Perspex.Base/PerspexObject.cs @@ -515,7 +515,7 @@ protected void RaisePropertyChanged( PerspexProperty property, object oldValue, object newValue, - BindingPriority priority) + BindingPriority priority = BindingPriority.LocalValue) { Contract.Requires(property != null); VerifyAccess(); diff --git a/src/Perspex.Controls/ScrollViewer.cs b/src/Perspex.Controls/ScrollViewer.cs index 8b5920b8e21..bbe774c325e 100644 --- a/src/Perspex.Controls/ScrollViewer.cs +++ b/src/Perspex.Controls/ScrollViewer.cs @@ -2,9 +2,7 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; -using System.Collections.Specialized; using System.Linq; -using System.Reactive.Disposables; using System.Reactive.Linq; using Perspex.Controls.Presenters; using Perspex.Controls.Primitives; @@ -51,37 +49,44 @@ public class ScrollViewer : ContentControl /// Defines the HorizontalScrollBarMaximum property. /// /// - /// There is no C# accessor for this property as it is intended to be bound to by a + /// There is no public C# accessor for this property as it is intended to be bound to by a /// in the control's template. /// - public static readonly StyledProperty HorizontalScrollBarMaximumProperty = - PerspexProperty.Register("HorizontalScrollBarMaximum"); + public static readonly DirectProperty HorizontalScrollBarMaximumProperty = + PerspexProperty.RegisterDirect( + nameof(HorizontalScrollBarMaximum), + o => o.HorizontalScrollBarMaximum); /// /// Defines the HorizontalScrollBarValue property. /// /// - /// There is no C# accessor for this property as it is intended to be bound to by a + /// There is no public C# accessor for this property as it is intended to be bound to by a /// in the control's template. /// - public static readonly StyledProperty HorizontalScrollBarValueProperty = - PerspexProperty.Register("HorizontalScrollBarValue"); + public static readonly DirectProperty HorizontalScrollBarValueProperty = + PerspexProperty.RegisterDirect( + nameof(HorizontalScrollBarValue), + o => o.HorizontalScrollBarValue, + (o, v) => o.HorizontalScrollBarValue = v); /// /// Defines the HorizontalScrollBarViewportSize property. /// /// - /// There is no C# accessor for this property as it is intended to be bound to by a + /// There is no public C# accessor for this property as it is intended to be bound to by a /// in the control's template. /// - public static readonly StyledProperty HorizontalScrollBarViewportSizeProperty = - PerspexProperty.Register("HorizontalScrollBarViewportSize"); + public static readonly DirectProperty HorizontalScrollBarViewportSizeProperty = + PerspexProperty.RegisterDirect( + nameof(HorizontalScrollBarViewportSize), + o => o.HorizontalScrollBarViewportSize); /// /// Defines the property. /// /// - /// There is no C# accessor for this property as it is intended to be bound to by a + /// There is no public C# accessor for this property as it is intended to be bound to by a /// in the control's template. /// public static readonly AttachedProperty HorizontalScrollBarVisibilityProperty = @@ -93,31 +98,38 @@ public class ScrollViewer : ContentControl /// Defines the VerticalScrollBarMaximum property. /// /// - /// There is no C# accessor for this property as it is intended to be bound to by a + /// There is no public C# accessor for this property as it is intended to be bound to by a /// in the control's template. /// - public static readonly StyledProperty VerticalScrollBarMaximumProperty = - PerspexProperty.Register("VerticalScrollBarMaximum"); + public static readonly DirectProperty VerticalScrollBarMaximumProperty = + PerspexProperty.RegisterDirect( + nameof(VerticalScrollBarMaximum), + o => o.VerticalScrollBarMaximum); /// /// Defines the VerticalScrollBarValue property. /// /// - /// There is no C# accessor for this property as it is intended to be bound to by a + /// There is no public C# accessor for this property as it is intended to be bound to by a /// in the control's template. /// - public static readonly StyledProperty VerticalScrollBarValueProperty = - PerspexProperty.Register("VerticalScrollBarValue"); + public static readonly DirectProperty VerticalScrollBarValueProperty = + PerspexProperty.RegisterDirect( + nameof(VerticalScrollBarValue), + o => o.VerticalScrollBarValue, + (o, v) => o.VerticalScrollBarValue = v); /// /// Defines the VerticalScrollBarViewportSize property. /// /// - /// There is no C# accessor for this property as it is intended to be bound to by a + /// There is no public C# accessor for this property as it is intended to be bound to by a /// in the control's template. /// - public static readonly StyledProperty VerticalScrollBarViewportSizeProperty = - PerspexProperty.Register("VerticalScrollBarViewportSize"); + public static readonly DirectProperty VerticalScrollBarViewportSizeProperty = + PerspexProperty.RegisterDirect( + nameof(VerticalScrollBarViewportSize), + o => o.VerticalScrollBarViewportSize); /// /// Defines the property. @@ -149,34 +161,6 @@ public ScrollViewer() this.GetObservable(ExtentProperty), this.GetObservable(ViewportProperty)) .Select(x => new { Extent = x[0], Viewport = x[1] }); - - Bind( - VerticalScrollBarViewportSizeProperty, - extentAndViewport.Select(x => Max((x.Viewport.Height / x.Extent.Height) * (x.Extent.Height - x.Viewport.Height), 0))); - - Bind( - HorizontalScrollBarViewportSizeProperty, - extentAndViewport.Select(x => Max((x.Viewport.Width / x.Extent.Width) * (x.Extent.Width - x.Viewport.Width), 0))); - - Bind( - HorizontalScrollBarMaximumProperty, - extentAndViewport.Select(x => Max(x.Extent.Width - x.Viewport.Width, 0))); - - Bind( - VerticalScrollBarMaximumProperty, - extentAndViewport.Select(x => Max(x.Extent.Height - x.Viewport.Height, 0))); - - this.GetObservable(OffsetProperty).Subscribe(x => - { - SetValue(HorizontalScrollBarValueProperty, x.X); - SetValue(VerticalScrollBarValueProperty, x.Y); - }); - - var scrollBarOffset = Observable.CombineLatest( - this.GetObservable(HorizontalScrollBarValueProperty), - this.GetObservable(VerticalScrollBarValueProperty)) - .Select(x => new Vector(x[0], x[1])) - .Subscribe(x => Offset = x); } /// @@ -184,8 +168,18 @@ public ScrollViewer() /// public Size Extent { - get { return _extent; } - private set { SetAndRaise(ExtentProperty, ref _extent, value); } + get + { + return _extent; + } + + private set + { + if (SetAndRaise(ExtentProperty, ref _extent, value)) + { + CalculatedPropertiesChanged(); + } + } } /// @@ -201,7 +195,11 @@ public Vector Offset set { value = ValidateOffset(this, value); - SetAndRaise(OffsetProperty, ref _offset, value); + + if (SetAndRaise(OffsetProperty, ref _offset, value)) + { + CalculatedPropertiesChanged(); + } } } @@ -241,6 +239,72 @@ public ScrollBarVisibility VerticalScrollBarVisibility set { SetValue(VerticalScrollBarVisibilityProperty, value); } } + /// + /// Gets the maximum horizontal scrollbar value. + /// + protected double HorizontalScrollBarMaximum + { + get { return Max(_extent.Width - _viewport.Width, 0); } + } + + /// + /// Gets or sets the horizontal scrollbar value. + /// + protected double HorizontalScrollBarValue + { + get { return _offset.X; } + set + { + if (_offset.X != value) + { + var old = Offset.X; + Offset = Offset.WithX(value); + RaisePropertyChanged(HorizontalScrollBarValueProperty, old, value); + } + } + } + + /// + /// Gets the size of the horizontal scrollbar viewport. + /// + protected double HorizontalScrollBarViewportSize + { + get { return Max((_viewport.Width / _extent.Width) * (_extent.Width - _viewport.Width), 0); } + } + + /// + /// Gets the maximum vertical scrollbar value. + /// + protected double VerticalScrollBarMaximum + { + get { return Max(_extent.Height - _viewport.Height, 0); } + } + + /// + /// Gets or sets the vertical scrollbar value. + /// + protected double VerticalScrollBarValue + { + get { return _offset.Y; } + set + { + if (_offset.Y != value) + { + var old = Offset.Y; + Offset = Offset.WithY(value); + RaisePropertyChanged(VerticalScrollBarValueProperty, old, value); + } + } + } + + /// + /// Gets the size of the vertical scrollbar viewport. + /// + protected double VerticalScrollBarViewportSize + { + get { return Max((_viewport.Height / _extent.Height) * (_extent.Height - _viewport.Height), 0); } + } + internal static Vector CoerceOffset(Size extent, Size viewport, Vector offset) { var maxX = Math.Max(extent.Width - viewport.Width, 0); @@ -274,5 +338,17 @@ private static Vector ValidateOffset(PerspexObject o, Vector value) return value; } } + + 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 properies. + RaisePropertyChanged(HorizontalScrollBarMaximumProperty, 0, HorizontalScrollBarMaximum); + RaisePropertyChanged(HorizontalScrollBarValueProperty, 0, HorizontalScrollBarValue); + RaisePropertyChanged(HorizontalScrollBarViewportSizeProperty, 0, HorizontalScrollBarViewportSize); + RaisePropertyChanged(VerticalScrollBarMaximumProperty, 0, VerticalScrollBarMaximum); + RaisePropertyChanged(VerticalScrollBarValueProperty, 0, VerticalScrollBarValue); + RaisePropertyChanged(VerticalScrollBarViewportSizeProperty, 0, VerticalScrollBarViewportSize); + } } }