diff --git a/demo/Ursa.Demo/Models/MenuKeys.cs b/demo/Ursa.Demo/Models/MenuKeys.cs
index 8532a7f..86d7fd5 100644
--- a/demo/Ursa.Demo/Models/MenuKeys.cs
+++ b/demo/Ursa.Demo/Models/MenuKeys.cs
@@ -14,6 +14,7 @@ public static class MenuKeys
public const string MenuKeyKeyGestureInput = "KeyGestureInput";
public const string MenuKeyLoading = "Loading";
public const string MenuKeyNavigation = "Navigation";
+ public const string MenuKeyNumericUpDown = "NumericUpDown";
public const string MenuKeyPagination = "Pagination";
public const string MenuKeyTagInput = "TagInput";
public const string MenuKeyTimeline = "Timeline";
diff --git a/demo/Ursa.Demo/Pages/NumericUpDownDemo.axaml b/demo/Ursa.Demo/Pages/NumericUpDownDemo.axaml
new file mode 100644
index 0000000..a16edcd
--- /dev/null
+++ b/demo/Ursa.Demo/Pages/NumericUpDownDemo.axaml
@@ -0,0 +1,14 @@
+
+
+
+
+
diff --git a/demo/Ursa.Demo/Pages/NumericUpDownDemo.axaml.cs b/demo/Ursa.Demo/Pages/NumericUpDownDemo.axaml.cs
new file mode 100644
index 0000000..4bdf06d
--- /dev/null
+++ b/demo/Ursa.Demo/Pages/NumericUpDownDemo.axaml.cs
@@ -0,0 +1,15 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using Ursa.Demo.ViewModels;
+
+namespace Ursa.Demo.Pages;
+
+public partial class NumericUpDownDemo : UserControl
+{
+ public NumericUpDownDemo()
+ {
+ InitializeComponent();
+ DataContext = new NumericUpDownDemoViewModel();
+ }
+}
\ No newline at end of file
diff --git a/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs b/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs
index d2c59ba..b18384f 100644
--- a/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs
+++ b/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs
@@ -36,6 +36,7 @@ public class MainViewViewModel : ViewModelBase
MenuKeys.MenuKeyKeyGestureInput => new KeyGestureInputDemoViewModel(),
MenuKeys.MenuKeyLoading => new LoadingDemoViewModel(),
MenuKeys.MenuKeyNavigation => new NavigationMenuDemoViewModel(),
+ MenuKeys.MenuKeyNumericUpDown => new NumericUpDownDemoViewModel(),
MenuKeys.MenuKeyPagination => new PaginationDemoViewModel(),
MenuKeys.MenuKeyTagInput => new TagInputDemoViewModel(),
MenuKeys.MenuKeyTimeline => new TimelineDemoViewModel(),
diff --git a/demo/Ursa.Demo/ViewModels/MenuViewModel.cs b/demo/Ursa.Demo/ViewModels/MenuViewModel.cs
index b2f04b0..957e943 100644
--- a/demo/Ursa.Demo/ViewModels/MenuViewModel.cs
+++ b/demo/Ursa.Demo/ViewModels/MenuViewModel.cs
@@ -23,6 +23,7 @@ public class MenuViewModel: ViewModelBase
new() { MenuHeader = "KeyGestureInput", Key = MenuKeys.MenuKeyKeyGestureInput },
new() { MenuHeader = "Loading", Key = MenuKeys.MenuKeyLoading },
new() { MenuHeader = "Navigation", Key = MenuKeys.MenuKeyNavigation },
+ new() { MenuHeader = "NumericUpDown", Key = MenuKeys.MenuKeyNumericUpDown },
new() { MenuHeader = "Pagination", Key = MenuKeys.MenuKeyPagination },
new() { MenuHeader = "TagInput", Key = MenuKeys.MenuKeyTagInput },
new() { MenuHeader = "Timeline", Key = MenuKeys.MenuKeyTimeline },
diff --git a/demo/Ursa.Demo/ViewModels/NumericUpDownDemoViewModel.cs b/demo/Ursa.Demo/ViewModels/NumericUpDownDemoViewModel.cs
new file mode 100644
index 0000000..9840cca
--- /dev/null
+++ b/demo/Ursa.Demo/ViewModels/NumericUpDownDemoViewModel.cs
@@ -0,0 +1,8 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+
+namespace Ursa.Demo.ViewModels;
+
+public class NumericUpDownDemoViewModel: ObservableObject
+{
+
+}
\ No newline at end of file
diff --git a/src/Ursa.Themes.Semi/Controls/NumericUpDown.axaml b/src/Ursa.Themes.Semi/Controls/NumericUpDown.axaml
new file mode 100644
index 0000000..53f60ce
--- /dev/null
+++ b/src/Ursa.Themes.Semi/Controls/NumericUpDown.axaml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Ursa.Themes.Semi/Controls/_index.axaml b/src/Ursa.Themes.Semi/Controls/_index.axaml
index f3b1ac5..8d9c5a1 100644
--- a/src/Ursa.Themes.Semi/Controls/_index.axaml
+++ b/src/Ursa.Themes.Semi/Controls/_index.axaml
@@ -12,6 +12,7 @@
+
diff --git a/src/Ursa/Controls/NumericUpDown/IntUpDown.cs b/src/Ursa/Controls/NumericUpDown/IntUpDown.cs
new file mode 100644
index 0000000..07ce4b6
--- /dev/null
+++ b/src/Ursa/Controls/NumericUpDown/IntUpDown.cs
@@ -0,0 +1,22 @@
+namespace Ursa.Controls;
+
+public class IntUpDown: NumericUpDownBase
+{
+ protected override Type StyleKeyOverride { get; } = typeof(NumericUpDown);
+
+ static IntUpDown()
+ {
+ MaximumProperty.OverrideDefaultValue(100);
+ }
+
+ protected override void Increase()
+ {
+ //throw new NotImplementedException();
+ Value += Maximum;
+ }
+
+ protected override void Decrease()
+ {
+ Value -= Maximum;
+ }
+}
\ No newline at end of file
diff --git a/src/Ursa/Controls/NumericUpDown/NumericUpDownBase.cs b/src/Ursa/Controls/NumericUpDown/NumericUpDownBase.cs
new file mode 100644
index 0000000..564a235
--- /dev/null
+++ b/src/Ursa/Controls/NumericUpDown/NumericUpDownBase.cs
@@ -0,0 +1,133 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Metadata;
+using Avalonia.Controls.Primitives;
+
+namespace Ursa.Controls;
+
+[TemplatePart(PART_Spinner, typeof(ButtonSpinner))]
+[TemplatePart(PART_TextBox, typeof(TextBox))]
+public abstract class NumericUpDown : TemplatedControl
+{
+ public const string PART_Spinner = "PART_Spinner";
+ public const string PART_TextBox = "PART_TextBox";
+
+ private Avalonia.Controls.NumericUpDown? _numericUpDown;
+ private ButtonSpinner? _spinner;
+ private TextBox? _textBox;
+
+ public static readonly StyledProperty TextEditableProperty = AvaloniaProperty.Register(
+ nameof(TextEditable), defaultValue: true);
+
+ public bool TextEditable
+ {
+ get => GetValue(TextEditableProperty);
+ set => SetValue(TextEditableProperty, value);
+ }
+
+ public static readonly StyledProperty IsReadOnlyProperty = AvaloniaProperty.Register(
+ nameof(IsReadOnly));
+
+ public bool IsReadOnly
+ {
+ get => GetValue(IsReadOnlyProperty);
+ set => SetValue(IsReadOnlyProperty, value);
+ }
+
+ public static readonly StyledProperty