Browse Source

Fix ScrollViewer.

Make various properties Direct properties, which gives them the correct
binding behavior.
pull/396/head
Steven Kirk 11 years ago
parent
commit
c052d389a9
  1. 27
      src/Perspex.Controls/Presenters/ScrollContentPresenter.cs
  2. 74
      src/Perspex.Controls/Primitives/RangeBase.cs
  3. 22
      src/Perspex.Controls/Primitives/Track.cs
  4. 37
      src/Perspex.Controls/ScrollViewer.cs
  5. 11
      tests/Perspex.Controls.UnitTests/Presenters/ScrollContentPresenterTests.cs

27
src/Perspex.Controls/Presenters/ScrollContentPresenter.cs

@ -21,19 +21,25 @@ namespace Perspex.Controls.Presenters
/// Defines the <see cref="Extent"/> property. /// Defines the <see cref="Extent"/> property.
/// </summary> /// </summary>
public static readonly PerspexProperty<Size> ExtentProperty = public static readonly PerspexProperty<Size> ExtentProperty =
ScrollViewer.ExtentProperty.AddOwner<ScrollContentPresenter>(); ScrollViewer.ExtentProperty.AddOwner<ScrollContentPresenter>(
o => o.Extent,
(o, v) => o.Extent = v);
/// <summary> /// <summary>
/// Defines the <see cref="Offset"/> property. /// Defines the <see cref="Offset"/> property.
/// </summary> /// </summary>
public static readonly PerspexProperty<Vector> OffsetProperty = public static readonly PerspexProperty<Vector> OffsetProperty =
ScrollViewer.OffsetProperty.AddOwner<ScrollContentPresenter>(); ScrollViewer.OffsetProperty.AddOwner<ScrollContentPresenter>(
o => o.Offset,
(o, v) => o.Offset = v);
/// <summary> /// <summary>
/// Defines the <see cref="Viewport"/> property. /// Defines the <see cref="Viewport"/> property.
/// </summary> /// </summary>
public static readonly PerspexProperty<Size> ViewportProperty = public static readonly PerspexProperty<Size> ViewportProperty =
ScrollViewer.ViewportProperty.AddOwner<ScrollContentPresenter>(); ScrollViewer.ViewportProperty.AddOwner<ScrollContentPresenter>(
o => o.Viewport,
(o, v) => o.Viewport = v);
/// <summary> /// <summary>
/// Defines the <see cref="CanScrollHorizontally"/> property. /// Defines the <see cref="CanScrollHorizontally"/> property.
@ -41,8 +47,11 @@ namespace Perspex.Controls.Presenters
public static readonly PerspexProperty<bool> CanScrollHorizontallyProperty = public static readonly PerspexProperty<bool> CanScrollHorizontallyProperty =
PerspexProperty.Register<ScrollContentPresenter, bool>("CanScrollHorizontally", true); PerspexProperty.Register<ScrollContentPresenter, bool>("CanScrollHorizontally", true);
private Size _extent;
private Size _measuredExtent; private Size _measuredExtent;
private Vector _offset;
private IDisposable _scrollableSubscription; private IDisposable _scrollableSubscription;
private Size _viewport;
/// <summary> /// <summary>
/// Initializes static members of the <see cref="ScrollContentPresenter"/> class. /// Initializes static members of the <see cref="ScrollContentPresenter"/> class.
@ -69,8 +78,8 @@ namespace Perspex.Controls.Presenters
/// </summary> /// </summary>
public Size Extent public Size Extent
{ {
get { return GetValue(ExtentProperty); } get { return _extent; }
private set { SetValue(ExtentProperty, value); } private set { SetAndRaise(ExtentProperty, ref _extent, value); }
} }
/// <summary> /// <summary>
@ -78,8 +87,8 @@ namespace Perspex.Controls.Presenters
/// </summary> /// </summary>
public Vector Offset public Vector Offset
{ {
get { return GetValue(OffsetProperty); } get { return _offset; }
set { SetValue(OffsetProperty, value); } set { SetAndRaise(OffsetProperty, ref _offset, value); }
} }
/// <summary> /// <summary>
@ -87,8 +96,8 @@ namespace Perspex.Controls.Presenters
/// </summary> /// </summary>
public Size Viewport public Size Viewport
{ {
get { return GetValue(ViewportProperty); } get { return _viewport; }
private set { SetValue(ViewportProperty, value); } private set { SetAndRaise(ViewportProperty, ref _viewport, value); }
} }
/// <summary> /// <summary>

74
src/Perspex.Controls/Primitives/RangeBase.cs

@ -15,34 +15,38 @@ namespace Perspex.Controls.Primitives
/// Defines the <see cref="Minimum"/> property. /// Defines the <see cref="Minimum"/> property.
/// </summary> /// </summary>
public static readonly PerspexProperty<double> MinimumProperty = public static readonly PerspexProperty<double> MinimumProperty =
PerspexProperty.Register<RangeBase, double>( PerspexProperty.RegisterDirect<RangeBase, double>(
nameof(Minimum), nameof(Minimum),
validate: ValidateMinimum); o => o.Minimum,
(o, v) => o.Minimum = v);
/// <summary> /// <summary>
/// Defines the <see cref="Maximum"/> property. /// Defines the <see cref="Maximum"/> property.
/// </summary> /// </summary>
public static readonly PerspexProperty<double> MaximumProperty = public static readonly PerspexProperty<double> MaximumProperty =
PerspexProperty.Register<RangeBase, double>( PerspexProperty.RegisterDirect<RangeBase, double>(
nameof(Maximum), nameof(Maximum),
defaultValue: 100.0, o => o.Maximum,
validate: ValidateMaximum); (o, v) => o.Maximum = v);
/// <summary> /// <summary>
/// Defines the <see cref="Value"/> property. /// Defines the <see cref="Value"/> property.
/// </summary> /// </summary>
public static readonly PerspexProperty<double> ValueProperty = public static readonly PerspexProperty<double> ValueProperty =
PerspexProperty.Register<RangeBase, double>( PerspexProperty.RegisterDirect<RangeBase, double>(
nameof(Value), nameof(Value),
validate: ValidateValue); o => o.Value,
(o, v) => o.Value = v);
private double _minimum;
private double _maximum = 100.0;
private double _value;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RangeBase"/> class. /// Initializes a new instance of the <see cref="RangeBase"/> class.
/// </summary> /// </summary>
public RangeBase() public RangeBase()
{ {
AffectsValidation(MinimumProperty, MaximumProperty, ValueProperty);
AffectsValidation(MaximumProperty, ValueProperty);
} }
/// <summary> /// <summary>
@ -50,8 +54,18 @@ namespace Perspex.Controls.Primitives
/// </summary> /// </summary>
public double Minimum public double Minimum
{ {
get { return GetValue(MinimumProperty); } get
set { SetValue(MinimumProperty, value); } {
return _minimum;
}
set
{
value = ValidateMinimum(value);
SetAndRaise(MinimumProperty, ref _minimum, value);
Maximum = ValidateMaximum(Maximum);
Value = ValidateValue(Value);
}
} }
/// <summary> /// <summary>
@ -59,8 +73,17 @@ namespace Perspex.Controls.Primitives
/// </summary> /// </summary>
public double Maximum public double Maximum
{ {
get { return GetValue(MaximumProperty); } get
set { SetValue(MaximumProperty, value); } {
return _maximum;
}
set
{
value = ValidateMaximum(value);
SetAndRaise(MaximumProperty, ref _maximum, value);
Value = ValidateValue(Value);
}
} }
/// <summary> /// <summary>
@ -68,8 +91,16 @@ namespace Perspex.Controls.Primitives
/// </summary> /// </summary>
public double Value public double Value
{ {
get { return GetValue(ValueProperty); } get
set { SetValue(ValueProperty, value); } {
return _value;
}
set
{
value = ValidateValue(value);
SetAndRaise(ValueProperty, ref _value, value);
}
} }
/// <summary> /// <summary>
@ -88,10 +119,9 @@ namespace Perspex.Controls.Primitives
/// <summary> /// <summary>
/// Validates the <see cref="Minimum"/> property. /// Validates the <see cref="Minimum"/> property.
/// </summary> /// </summary>
/// <param name="sender">The RangeBase control.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
/// <returns>The coerced value.</returns> /// <returns>The coerced value.</returns>
private static double ValidateMinimum(RangeBase sender, double value) private double ValidateMinimum(double value)
{ {
ValidateDouble(value, "Minimum"); ValidateDouble(value, "Minimum");
return value; return value;
@ -100,25 +130,23 @@ namespace Perspex.Controls.Primitives
/// <summary> /// <summary>
/// Validates/coerces the <see cref="Maximum"/> property. /// Validates/coerces the <see cref="Maximum"/> property.
/// </summary> /// </summary>
/// <param name="sender">The RangeBase control.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
/// <returns>The coerced value.</returns> /// <returns>The coerced value.</returns>
private static double ValidateMaximum(RangeBase sender, double value) private double ValidateMaximum(double value)
{ {
ValidateDouble(value, "Maximum"); ValidateDouble(value, "Maximum");
return Math.Max(value, sender.Minimum); return Math.Max(value, Minimum);
} }
/// <summary> /// <summary>
/// Validates/coerces the <see cref="Value"/> property. /// Validates/coerces the <see cref="Value"/> property.
/// </summary> /// </summary>
/// <param name="sender">The RangeBase control.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
/// <returns>The coerced value.</returns> /// <returns>The coerced value.</returns>
private static double ValidateValue(RangeBase sender, double value) private double ValidateValue(double value)
{ {
ValidateDouble(value, "Value"); ValidateDouble(value, "Value");
return MathUtilities.Clamp(value, sender.Minimum, sender.Maximum); return MathUtilities.Clamp(value, Minimum, Maximum);
} }
} }
} }

22
src/Perspex.Controls/Primitives/Track.cs

@ -11,13 +11,13 @@ namespace Perspex.Controls.Primitives
public class Track : Control public class Track : Control
{ {
public static readonly PerspexProperty<double> MinimumProperty = public static readonly PerspexProperty<double> MinimumProperty =
RangeBase.MinimumProperty.AddOwner<Track>(); RangeBase.MinimumProperty.AddOwner<Track>(o => o.Minimum, (o,v) => o.Minimum = v);
public static readonly PerspexProperty<double> MaximumProperty = public static readonly PerspexProperty<double> MaximumProperty =
RangeBase.MaximumProperty.AddOwner<Track>(); RangeBase.MaximumProperty.AddOwner<Track>(o => o.Maximum, (o, v) => o.Maximum = v);
public static readonly PerspexProperty<double> ValueProperty = public static readonly PerspexProperty<double> ValueProperty =
RangeBase.ValueProperty.AddOwner<Track>(); RangeBase.ValueProperty.AddOwner<Track>(o => o.Value, (o, v) => o.Value = v);
public static readonly PerspexProperty<double> ViewportSizeProperty = public static readonly PerspexProperty<double> ViewportSizeProperty =
ScrollBar.ViewportSizeProperty.AddOwner<Track>(); ScrollBar.ViewportSizeProperty.AddOwner<Track>();
@ -28,6 +28,10 @@ namespace Perspex.Controls.Primitives
public static readonly PerspexProperty<Thumb> ThumbProperty = public static readonly PerspexProperty<Thumb> ThumbProperty =
PerspexProperty.Register<Track, Thumb>("Thumb"); PerspexProperty.Register<Track, Thumb>("Thumb");
private double _minimum;
private double _maximum = 100.0;
private double _value;
static Track() static Track()
{ {
AffectsArrange(MinimumProperty); AffectsArrange(MinimumProperty);
@ -57,20 +61,20 @@ namespace Perspex.Controls.Primitives
public double Minimum public double Minimum
{ {
get { return GetValue(MinimumProperty); } get { return _minimum; }
set { SetValue(MinimumProperty, value); } set { SetAndRaise(MinimumProperty, ref _minimum, value); }
} }
public double Maximum public double Maximum
{ {
get { return GetValue(MaximumProperty); } get { return _maximum; }
set { SetValue(MaximumProperty, value); } set { SetAndRaise(MaximumProperty, ref _maximum, value); }
} }
public double Value public double Value
{ {
get { return GetValue(ValueProperty); } get { return _value; }
set { SetValue(ValueProperty, value); } set { SetAndRaise(ValueProperty, ref _value, value); }
} }
public double ViewportSize public double ViewportSize

37
src/Perspex.Controls/ScrollViewer.cs

@ -26,19 +26,26 @@ namespace Perspex.Controls
/// Defines the <see cref="Extent"/> property. /// Defines the <see cref="Extent"/> property.
/// </summary> /// </summary>
public static readonly PerspexProperty<Size> ExtentProperty = public static readonly PerspexProperty<Size> ExtentProperty =
PerspexProperty.Register<ScrollViewer, Size>(nameof(Extent)); PerspexProperty.RegisterDirect<ScrollViewer, Size>(nameof(Extent),
o => o.Extent,
(o, v) => o.Extent = v);
/// <summary> /// <summary>
/// Defines the <see cref="Offset"/> property. /// Defines the <see cref="Offset"/> property.
/// </summary> /// </summary>
public static readonly PerspexProperty<Vector> OffsetProperty = public static readonly PerspexProperty<Vector> OffsetProperty =
PerspexProperty.Register<ScrollViewer, Vector>(nameof(Offset), validate: ValidateOffset); PerspexProperty.RegisterDirect<ScrollViewer, Vector>(
nameof(Offset),
o => o.Offset,
(o, v) => o.Offset = v);
/// <summary> /// <summary>
/// Defines the <see cref="Viewport"/> property. /// Defines the <see cref="Viewport"/> property.
/// </summary> /// </summary>
public static readonly PerspexProperty<Size> ViewportProperty = public static readonly PerspexProperty<Size> ViewportProperty =
PerspexProperty.Register<ScrollViewer, Size>(nameof(Viewport)); PerspexProperty.RegisterDirect<ScrollViewer, Size>(nameof(Viewport),
o => o.Viewport,
(o, v) => o.Viewport = v);
/// <summary> /// <summary>
/// Defines the HorizontalScrollBarMaximum property. /// Defines the HorizontalScrollBarMaximum property.
@ -120,6 +127,10 @@ namespace Perspex.Controls
nameof(VerticalScrollBarVisibility), nameof(VerticalScrollBarVisibility),
ScrollBarVisibility.Auto); ScrollBarVisibility.Auto);
private Size _extent;
private Vector _offset;
private Size _viewport;
/// <summary> /// <summary>
/// Initializes static members of the <see cref="ScrollViewer"/> class. /// Initializes static members of the <see cref="ScrollViewer"/> class.
/// </summary> /// </summary>
@ -173,8 +184,8 @@ namespace Perspex.Controls
/// </summary> /// </summary>
public Size Extent public Size Extent
{ {
get { return GetValue(ExtentProperty); } get { return _extent; }
private set { SetValue(ExtentProperty, value); } private set { SetAndRaise(ExtentProperty, ref _extent, value); }
} }
/// <summary> /// <summary>
@ -182,8 +193,16 @@ namespace Perspex.Controls
/// </summary> /// </summary>
public Vector Offset public Vector Offset
{ {
get { return GetValue(OffsetProperty); } get
set { SetValue(OffsetProperty, value); } {
return _offset;
}
set
{
value = ValidateOffset(this, value);
SetAndRaise(OffsetProperty, ref _offset, value);
}
} }
/// <summary> /// <summary>
@ -191,8 +210,8 @@ namespace Perspex.Controls
/// </summary> /// </summary>
public Size Viewport public Size Viewport
{ {
get { return GetValue(ViewportProperty); } get { return _viewport; }
private set { SetValue(ViewportProperty, value); } private set { SetAndRaise(ViewportProperty, ref _viewport, value); }
} }
/// <summary> /// <summary>

11
tests/Perspex.Controls.UnitTests/Presenters/ScrollContentPresenterTests.cs

@ -218,17 +218,6 @@ namespace Perspex.Controls.UnitTests.Presenters
Assert.False(target.IsArrangeValid); Assert.False(target.IsArrangeValid);
} }
[Fact]
public void Offset_Should_Be_Coerced_To_Viewport()
{
var target = new ScrollContentPresenter();
target.SetValue(ScrollContentPresenter.ExtentProperty, new Size(20, 20));
target.SetValue(ScrollContentPresenter.ViewportProperty, new Size(10, 10));
target.Offset = new Vector(12, 12);
Assert.Equal(new Vector(10, 10), target.Offset);
}
[Fact] [Fact]
public void BringDescendentIntoView_Should_Update_Offset() public void BringDescendentIntoView_Should_Update_Offset()
{ {

Loading…
Cancel
Save