diff --git a/src/Avalonia.Controls/StackPanel.cs b/src/Avalonia.Controls/StackPanel.cs
index 964a1055df..89afb50b38 100644
--- a/src/Avalonia.Controls/StackPanel.cs
+++ b/src/Avalonia.Controls/StackPanel.cs
@@ -4,7 +4,11 @@
// Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
using System;
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia.Controls.Primitives;
using Avalonia.Input;
+using Avalonia.Interactivity;
using Avalonia.Layout;
namespace Avalonia.Controls
@@ -12,7 +16,7 @@ namespace Avalonia.Controls
///
/// A panel which lays out its children horizontally or vertically.
///
- public class StackPanel : Panel, INavigableContainer
+ public class StackPanel : Panel, INavigableContainer, IScrollSnapPointsInfo
{
///
/// Defines the property.
@@ -26,6 +30,34 @@ namespace Avalonia.Controls
public static readonly StyledProperty OrientationProperty =
StackLayout.OrientationProperty.AddOwner();
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty AreHorizontalSnapPointsRegularProperty =
+ AvaloniaProperty.Register(nameof(AreHorizontalSnapPointsRegular));
+
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty AreVerticalSnapPointsRegularProperty =
+ AvaloniaProperty.Register(nameof(AreVerticalSnapPointsRegular));
+
+ ///
+ /// Defines the event.
+ ///
+ public static readonly RoutedEvent HorizontalSnapPointsChangedEvent =
+ RoutedEvent.Register(
+ nameof(HorizontalSnapPointsChanged),
+ RoutingStrategies.Bubble);
+
+ ///
+ /// Defines the event.
+ ///
+ public static readonly RoutedEvent VerticalSnapPointsChangedEvent =
+ RoutedEvent.Register(
+ nameof(VerticalSnapPointsChanged),
+ RoutingStrategies.Bubble);
+
///
/// Initializes static members of the class.
///
@@ -53,6 +85,31 @@ namespace Avalonia.Controls
set { SetValue(OrientationProperty, value); }
}
+ public event EventHandler? HorizontalSnapPointsChanged
+ {
+ add => AddHandler(HorizontalSnapPointsChangedEvent, value);
+ remove => RemoveHandler(HorizontalSnapPointsChangedEvent, value);
+ }
+
+
+ public event EventHandler? VerticalSnapPointsChanged
+ {
+ add => AddHandler(VerticalSnapPointsChangedEvent, value);
+ remove => RemoveHandler(VerticalSnapPointsChangedEvent, value);
+ }
+
+ public bool AreHorizontalSnapPointsRegular
+ {
+ get { return GetValue(AreHorizontalSnapPointsRegularProperty); }
+ set { SetValue(AreHorizontalSnapPointsRegularProperty, value); }
+ }
+
+ public bool AreVerticalSnapPointsRegular
+ {
+ get { return GetValue(AreVerticalSnapPointsRegularProperty); }
+ set { SetValue(AreVerticalSnapPointsRegularProperty, value); }
+ }
+
///
/// Gets the next control in the specified direction.
///
@@ -274,6 +331,8 @@ namespace Avalonia.Controls
ArrangeChild(child, rcChild, finalSize, Orientation);
}
+ RaiseEvent(new RoutedEventArgs(Orientation == Orientation.Horizontal ? HorizontalSnapPointsChangedEvent : VerticalSnapPointsChangedEvent));
+
return finalSize;
}
@@ -285,5 +344,122 @@ namespace Avalonia.Controls
{
child.Arrange(rect);
}
+
+ public IReadOnlyList GetIrregularSnapPoints(Orientation orientation, SnapPointsAlignment snapPointsAlignment)
+ {
+ var snapPoints = new List();
+
+ switch (orientation)
+ {
+ case Orientation.Horizontal:
+ if (AreHorizontalSnapPointsRegular)
+ throw new InvalidOperationException();
+ if (Orientation == Orientation.Horizontal)
+ {
+ foreach(var child in VisualChildren)
+ {
+ double snapPoint = 0;
+
+ switch (snapPointsAlignment)
+ {
+ case SnapPointsAlignment.Near:
+ snapPoint = child.Bounds.Left;
+ break;
+ case SnapPointsAlignment.Center:
+ snapPoint = child.Bounds.Center.X;
+ break;
+ case SnapPointsAlignment.Far:
+ snapPoint = child.Bounds.Right;
+ break;
+ }
+
+ snapPoints.Add(snapPoint);
+ }
+ }
+ break;
+ case Orientation.Vertical:
+ if (AreVerticalSnapPointsRegular)
+ throw new InvalidOperationException();
+ if (Orientation == Orientation.Vertical)
+ {
+ foreach (var child in VisualChildren)
+ {
+ double snapPoint = 0;
+
+ switch (snapPointsAlignment)
+ {
+ case SnapPointsAlignment.Near:
+ snapPoint = child.Bounds.Top;
+ break;
+ case SnapPointsAlignment.Center:
+ snapPoint = child.Bounds.Center.Y;
+ break;
+ case SnapPointsAlignment.Far:
+ snapPoint = child.Bounds.Bottom;
+ break;
+ }
+
+ snapPoints.Add(snapPoint);
+ }
+ }
+ break;
+ }
+
+ return snapPoints;
+ }
+
+ public double GetRegularSnapPoints(Orientation orientation, SnapPointsAlignment snapPointsAlignment, out double offset)
+ {
+ offset = 0f;
+ var firstChild = VisualChildren.FirstOrDefault();
+
+ if(firstChild == null)
+ {
+ return 0;
+ }
+
+ double snapPoint = 0;
+
+ switch (Orientation)
+ {
+ case Orientation.Horizontal:
+ if (!AreHorizontalSnapPointsRegular)
+ throw new InvalidOperationException();
+
+ snapPoint = firstChild.Bounds.Width;
+ switch (snapPointsAlignment)
+ {
+ case SnapPointsAlignment.Near:
+ offset = firstChild.Bounds.Left;
+ break;
+ case SnapPointsAlignment.Center:
+ offset = firstChild.Bounds.Center.X;
+ break;
+ case SnapPointsAlignment.Far:
+ offset = firstChild.Bounds.Right;
+ break;
+ }
+ break;
+ case Orientation.Vertical:
+ if (!AreVerticalSnapPointsRegular)
+ throw new InvalidOperationException();
+ snapPoint = firstChild.Bounds.Height;
+ switch (snapPointsAlignment)
+ {
+ case SnapPointsAlignment.Near:
+ offset = firstChild.Bounds.Top;
+ break;
+ case SnapPointsAlignment.Center:
+ offset = firstChild.Bounds.Center.Y;
+ break;
+ case SnapPointsAlignment.Far:
+ offset = firstChild.Bounds.Bottom;
+ break;
+ }
+ break;
+ }
+
+ return snapPoint;
+ }
}
}