diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj
index 37f9da0c43..a3d7a0cdce 100644
--- a/samples/ControlCatalog/ControlCatalog.csproj
+++ b/samples/ControlCatalog/ControlCatalog.csproj
@@ -35,6 +35,9 @@
Designer
+
+ Designer
+
Designer
@@ -164,6 +167,9 @@
ToolTipPage.xaml
+
+ ButtonSpinnerPage.xaml
+
diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index 060369e404..142d0d42b1 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -7,6 +7,7 @@
+
diff --git a/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml b/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml
new file mode 100644
index 0000000000..1797fb48bc
--- /dev/null
+++ b/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml
@@ -0,0 +1,24 @@
+
+
+
+ ButtonSpinner
+ The ButtonSpinner control allows you to add button spinners to any element and then respond to the Spin event to manipulate that element.
+
+
+ AllowSpin
+ ShowButtonSpinner
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs b/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs
new file mode 100644
index 0000000000..1f753ab3ea
--- /dev/null
+++ b/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs
@@ -0,0 +1,54 @@
+using System;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+ public class ButtonSpinnerPage : UserControl
+ {
+ public ButtonSpinnerPage()
+ {
+ this.InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ private void OnSpin(object sender, SpinEventArgs e)
+ {
+ var spinner = (ButtonSpinner)sender;
+ var txtBox = (TextBlock)spinner.Content;
+
+ int value = Array.IndexOf(_mountains, txtBox.Text);
+ if (e.Direction == SpinDirection.Increase)
+ value++;
+ else
+ value--;
+
+ if (value < 0)
+ value = _mountains.Length - 1;
+ else if (value >= _mountains.Length)
+ value = 0;
+
+ txtBox.Text = _mountains[value];
+ }
+
+ private readonly string[] _mountains = new[]
+ {
+ "Everest",
+ "K2 (Mount Godwin Austen)",
+ "Kangchenjunga",
+ "Lhotse",
+ "Makalu",
+ "Cho Oyu",
+ "Dhaulagiri",
+ "Manaslu",
+ "Nanga Parbat",
+ "Annapurna"
+ };
+ }
+}
diff --git a/src/Avalonia.Controls/ButtonSpinner.cs b/src/Avalonia.Controls/ButtonSpinner.cs
new file mode 100644
index 0000000000..3ce81e0b12
--- /dev/null
+++ b/src/Avalonia.Controls/ButtonSpinner.cs
@@ -0,0 +1,258 @@
+using System;
+using Avalonia.Controls.Primitives;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+
+namespace Avalonia.Controls
+{
+ public enum Location
+ {
+ Left,
+ Right
+ }
+
+ ///
+ /// Represents a spinner control that includes two Buttons.
+ ///
+ public class ButtonSpinner : Spinner
+ {
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty AllowSpinProperty =
+ AvaloniaProperty.Register(nameof(AllowSpin), true);
+
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty ShowButtonSpinnerProperty =
+ AvaloniaProperty.Register(nameof(ShowButtonSpinner), true);
+
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty ButtonSpinnerLocationProperty =
+ AvaloniaProperty.Register(nameof(ButtonSpinnerLocation), Location.Right);
+
+ private Button _decreaseButton;
+ ///
+ /// Gets or sets the DecreaseButton template part.
+ ///
+ private Button DecreaseButton
+ {
+ get { return _decreaseButton; }
+ set
+ {
+ if (_decreaseButton != null)
+ {
+ _decreaseButton.Click -= OnButtonClick;
+ }
+ _decreaseButton = value;
+ if (_decreaseButton != null)
+ {
+ _decreaseButton.Click += OnButtonClick;
+ }
+ }
+ }
+
+ private Button _increaseButton;
+ ///
+ /// Gets or sets the IncreaseButton template part.
+ ///
+ private Button IncreaseButton
+ {
+ get
+ {
+ return _increaseButton;
+ }
+ set
+ {
+ if (_increaseButton != null)
+ {
+ _increaseButton.Click -= OnButtonClick;
+ }
+ _increaseButton = value;
+ if (_increaseButton != null)
+ {
+ _increaseButton.Click += OnButtonClick;
+ }
+ }
+ }
+
+ ///
+ /// Initializes static members of the class.
+ ///
+ static ButtonSpinner()
+ {
+ AllowSpinProperty.Changed.Subscribe(AllowSpinChanged);
+ PseudoClass(ButtonSpinnerLocationProperty, location => location == Location.Left, ":left");
+ PseudoClass(ButtonSpinnerLocationProperty, location => location == Location.Right, ":right");
+ }
+
+ ///
+ /// Gets or sets a value indicating whether the should allow to spin.
+ ///
+ public bool AllowSpin
+ {
+ get { return GetValue(AllowSpinProperty); }
+ set { SetValue(AllowSpinProperty, value); }
+ }
+
+ ///
+ /// Gets or sets a value indicating whether the spin buttons should be shown.
+ ///
+ public bool ShowButtonSpinner
+ {
+ get { return GetValue(ShowButtonSpinnerProperty); }
+ set { SetValue(ShowButtonSpinnerProperty, value); }
+ }
+
+ ///
+ /// Gets or sets current location of the .
+ ///
+ public Location ButtonSpinnerLocation
+ {
+ get { return GetValue(ButtonSpinnerLocationProperty); }
+ set { SetValue(ButtonSpinnerLocationProperty, value); }
+ }
+
+ ///
+ protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
+ {
+ IncreaseButton = e.NameScope.Find