diff --git a/Terminal.Gui/Views/NumericUpDown.cs b/Terminal.Gui/Views/NumericUpDown.cs
new file mode 100644
index 000000000..279cfd6cf
--- /dev/null
+++ b/Terminal.Gui/Views/NumericUpDown.cs
@@ -0,0 +1,251 @@
+#nullable enable
+using System.ComponentModel;
+
+namespace Terminal.Gui;
+
+///
+/// Enables the user to increase or decrease a value with the mouse or keyboard.
+///
+///
+/// Supports the following types: , , , ,
+/// . Attempting to use any other type will result in an .
+///
+public class NumericUpDown : View where T : notnull
+{
+ private readonly Button _down;
+
+ // TODO: Use a TextField instead of a Label
+ private readonly View _number;
+ private readonly Button _up;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ public NumericUpDown ()
+ {
+ Type type = typeof (T);
+
+ if (!(type == typeof (object)
+ || type == typeof (int)
+ || type == typeof (long)
+ || type == typeof (double)
+ || type == typeof (float)
+ || type == typeof (double)
+ || type == typeof (decimal)))
+ {
+ throw new InvalidOperationException ("T must be a numeric type that supports addition and subtraction.");
+ }
+
+ // `object` is supported only for AllViewsTester
+ if (type != typeof (object))
+ {
+ Increment = (dynamic)1;
+ Value = (dynamic)0;
+ }
+
+ Width = Dim.Auto (DimAutoStyle.Content);
+ Height = Dim.Auto (DimAutoStyle.Content);
+
+ _down = new ()
+ {
+ Height = 1,
+ Width = 1,
+ NoPadding = true,
+ NoDecorations = true,
+ Title = $"{Glyphs.DownArrow}",
+ WantContinuousButtonPressed = true,
+ CanFocus = false,
+ ShadowStyle = ShadowStyle.None
+ };
+
+ _number = new ()
+ {
+ Text = Value?.ToString () ?? "Err",
+ X = Pos.Right (_down),
+ Y = Pos.Top (_down),
+ Width = Dim.Auto (minimumContentDim: Dim.Func (() => string.Format (Format, Value).Length)),
+ Height = 1,
+ TextAlignment = Alignment.Center,
+ CanFocus = true
+ };
+
+ _up = new ()
+ {
+ X = Pos.Right (_number),
+ Y = Pos.Top (_number),
+ Height = 1,
+ Width = 1,
+ NoPadding = true,
+ NoDecorations = true,
+ Title = $"{Glyphs.UpArrow}",
+ WantContinuousButtonPressed = true,
+ CanFocus = false,
+ ShadowStyle = ShadowStyle.None
+ };
+
+ CanFocus = true;
+
+ _down.Accept += OnDownButtonOnAccept;
+ _up.Accept += OnUpButtonOnAccept;
+
+ Add (_down, _number, _up);
+
+ AddCommand (
+ Command.ScrollUp,
+ () =>
+ {
+ if (type == typeof (object))
+ {
+ return false;
+ }
+
+ if (Value is { })
+ {
+ Value = (dynamic)Value + (dynamic)Increment;
+ }
+
+ return true;
+ });
+
+ AddCommand (
+ Command.ScrollDown,
+ () =>
+ {
+ if (type == typeof (object))
+ {
+ return false;
+ }
+
+ if (Value is { })
+ {
+ Value = (dynamic)Value - (dynamic)Increment;
+ }
+
+ return true;
+ });
+
+ KeyBindings.Add (Key.CursorUp, Command.ScrollUp);
+ KeyBindings.Add (Key.CursorDown, Command.ScrollDown);
+
+ SetText ();
+
+ return;
+
+ void OnDownButtonOnAccept (object? s, HandledEventArgs e) { InvokeCommand (Command.ScrollDown); }
+
+ void OnUpButtonOnAccept (object? s, HandledEventArgs e) { InvokeCommand (Command.ScrollUp); }
+ }
+
+ private T _value = default!;
+
+ ///
+ /// Gets or sets the value that will be incremented or decremented.
+ ///
+ ///
+ ///
+ /// and events are raised when the value changes.
+ /// The event can be canceled the change setting
+ /// .Cancel to .
+ ///
+ ///
+ public T Value
+ {
+ get => _value;
+ set
+ {
+ if (_value.Equals (value))
+ {
+ return;
+ }
+
+ T oldValue = value;
+ CancelEventArgs args = new (in _value, ref value);
+ ValueChanging?.Invoke (this, args);
+
+ if (args.Cancel)
+ {
+ return;
+ }
+
+ _value = value;
+ SetText ();
+ ValueChanged?.Invoke (this, new (in value));
+ }
+ }
+
+ ///
+ /// Raised when the value is about to change. Set .Cancel to true to prevent the
+ /// change.
+ ///
+ public event EventHandler>? ValueChanging;
+
+ ///
+ /// Raised when the value has changed.
+ ///
+ public event EventHandler>? ValueChanged;
+
+ private string _format = "{0}";
+
+ ///
+ /// Gets or sets the format string used to display the value. The default is "{0}".
+ ///
+ public string Format
+ {
+ get => _format;
+ set
+ {
+ if (_format == value)
+ {
+ return;
+ }
+
+ _format = value;
+
+ FormatChanged?.Invoke (this, new (value));
+ SetText ();
+ }
+ }
+
+ ///
+ /// Raised when has changed.
+ ///
+ public event EventHandler>? FormatChanged;
+
+ private void SetText ()
+ {
+ _number.Text = string.Format (Format, _value);
+ Text = _number.Text;
+ }
+
+ private T _increment;
+
+ ///
+ ///
+ public T Increment
+ {
+ get => _increment;
+ set
+ {
+ if ((dynamic)_increment == (dynamic)value)
+ {
+ return;
+ }
+
+ _increment = value;
+
+ IncrementChanged?.Invoke (this, new (value));
+ }
+ }
+
+ ///
+ /// Raised when has changed.
+ ///
+ public event EventHandler>? IncrementChanged;
+}
+
+///
+/// Enables the user to increase or decrease an by clicking on the up or down buttons.
+///
+public class NumericUpDown : NumericUpDown
+{ }
diff --git a/UICatalog/Scenarios/AdornmentEditor.cs b/UICatalog/Scenarios/AdornmentEditor.cs
index bae41aceb..e941a8a84 100644
--- a/UICatalog/Scenarios/AdornmentEditor.cs
+++ b/UICatalog/Scenarios/AdornmentEditor.cs
@@ -78,10 +78,10 @@ public class AdornmentEditor : View
AdornmentChanged?.Invoke (this, EventArgs.Empty);
}
- private Buttons.NumericUpDown _topEdit;
- private Buttons.NumericUpDown _leftEdit;
- private Buttons.NumericUpDown _bottomEdit;
- private Buttons.NumericUpDown _rightEdit;
+ private NumericUpDown _topEdit;
+ private NumericUpDown _leftEdit;
+ private NumericUpDown _bottomEdit;
+ private NumericUpDown _rightEdit;
public AdornmentEditor ()
{
@@ -102,6 +102,7 @@ public class AdornmentEditor : View
_topEdit = new ()
{
X = Pos.Center (), Y = 0,
+ Format = "{0, 2}",
Enabled = false
};
@@ -110,7 +111,8 @@ public class AdornmentEditor : View
_leftEdit = new ()
{
- X = Pos.Left (_topEdit) - Pos.Func (() => _topEdit.Digits) - 2, Y = Pos.Bottom (_topEdit),
+ X = Pos.Left (_topEdit) - Pos.Func (() => _topEdit.Text.Length) - 2, Y = Pos.Bottom (_topEdit),
+ Format = _topEdit.Format,
Enabled = false
};
@@ -120,6 +122,7 @@ public class AdornmentEditor : View
_rightEdit = new ()
{
X = Pos.Right (_leftEdit) + 5, Y = Pos.Bottom (_topEdit),
+ Format = _topEdit.Format,
Enabled = false
};
@@ -129,6 +132,7 @@ public class AdornmentEditor : View
_bottomEdit = new ()
{
X = Pos.Center (), Y = Pos.Bottom (_leftEdit),
+ Format = _topEdit.Format,
Enabled = false
};
diff --git a/UICatalog/Scenarios/Buttons.cs b/UICatalog/Scenarios/Buttons.cs
index 5685913aa..8edcdf42b 100644
--- a/UICatalog/Scenarios/Buttons.cs
+++ b/UICatalog/Scenarios/Buttons.cs
@@ -336,8 +336,6 @@ public class Buttons : Scenario
Value = 69,
X = Pos.Right (label) + 1,
Y = Pos.Top (label),
- Width = 5,
- Height = 1
};
numericUpDown.ValueChanged += NumericUpDown_ValueChanged;
@@ -390,164 +388,24 @@ public class Buttons : Scenario
enableCB.Toggle += (s, e) => { repeatButton.Enabled = !repeatButton.Enabled; };
main.Add (label, repeatButton, enableCB);
- main.Ready += (s, e) => radioGroup.Refresh ();
+ var decNumericUpDown = new NumericUpDown
+ {
+ Value = 911,
+ Increment = 1,
+ Format = "{0:X}",
+ X = 0,
+ Y = Pos.Bottom (enableCB) + 1,
+ };
+
+ main.Add (decNumericUpDown);
+
+ main.Ready += (s, e) =>
+ {
+ radioGroup.Refresh ();
+ };
Application.Run (main);
main.Dispose ();
Application.Shutdown ();
}
-
- ///
- /// Enables the user to increase or decrease a value by clicking on the up or down buttons.
- ///
- ///
- /// Supports the following types: , , , , .
- /// Supports only one digit of precision.
- ///
- public class NumericUpDown : View
- {
- private readonly Button _down;
- // TODO: Use a TextField instead of a Label
- private readonly View _number;
- private readonly Button _up;
-
- public NumericUpDown ()
- {
- Type type = typeof (T);
- if (!(type == typeof (int) || type == typeof (long) || type == typeof (float) || type == typeof (double) || type == typeof (decimal)))
- {
- throw new InvalidOperationException ("T must be a numeric type that supports addition and subtraction.");
- }
-
- Width = Dim.Auto (DimAutoStyle.Content); //Dim.Function (() => Digits + 2); // button + 3 for number + button
- Height = Dim.Auto (DimAutoStyle.Content);
-
- _down = new ()
- {
- Height = 1,
- Width = 1,
- NoPadding = true,
- NoDecorations = true,
- Title = $"{CM.Glyphs.DownArrow}",
- WantContinuousButtonPressed = true,
- CanFocus = false,
- ShadowStyle = ShadowStyle.None,
- };
-
- _number = new ()
- {
- Text = Value.ToString (),
- X = Pos.Right (_down),
- Y = Pos.Top (_down),
- Width = Dim.Func (() => Digits),
- Height = 1,
- TextAlignment = Alignment.Center,
- CanFocus = true
- };
-
- _up = new ()
- {
- X = Pos.AnchorEnd (),
- Y = Pos.Top (_number),
- Height = 1,
- Width = 1,
- NoPadding = true,
- NoDecorations = true,
- Title = $"{CM.Glyphs.UpArrow}",
- WantContinuousButtonPressed = true,
- CanFocus = false,
- ShadowStyle = ShadowStyle.None,
- };
-
- CanFocus = true;
-
- _down.Accept += OnDownButtonOnAccept;
- _up.Accept += OnUpButtonOnAccept;
-
- Add (_down, _number, _up);
-
-
- AddCommand (Command.ScrollUp, () =>
- {
- Value = (dynamic)Value + 1;
- _number.Text = Value.ToString ();
-
- return true;
- });
- AddCommand (Command.ScrollDown, () =>
- {
- Value = (dynamic)Value - 1;
- _number.Text = Value.ToString ();
-
- return true;
- });
-
- KeyBindings.Add (Key.CursorUp, Command.ScrollUp);
- KeyBindings.Add (Key.CursorDown, Command.ScrollDown);
-
- return;
-
- void OnDownButtonOnAccept (object s, HandledEventArgs e)
- {
- InvokeCommand (Command.ScrollDown);
- }
-
- void OnUpButtonOnAccept (object s, HandledEventArgs e)
- {
- InvokeCommand (Command.ScrollUp);
- }
- }
-
- private void _up_Enter (object sender, FocusEventArgs e)
- {
- throw new NotImplementedException ();
- }
-
- private T _value;
-
- ///
- /// The value that will be incremented or decremented.
- ///
- public T Value
- {
- get => _value;
- set
- {
- if (_value.Equals (value))
- {
- return;
- }
-
- T oldValue = value;
- CancelEventArgs args = new (ref _value, ref value);
- ValueChanging?.Invoke (this, args);
-
- if (args.Cancel)
- {
- return;
- }
-
- _value = value;
- _number.Text = _value.ToString ()!;
- ValueChanged?.Invoke (this, new (in _value));
- }
- }
-
- ///
- /// Fired when the value is about to change. Set to true to prevent the change.
- ///
- [CanBeNull]
- public event EventHandler> ValueChanging;
-
- ///
- /// Fired when the value has changed.
- ///
- [CanBeNull]
- public event EventHandler> ValueChanged;
-
- ///
- /// The number of digits to display. The will be resized to fit this number of characters plus the buttons. The default is 3.
- ///
- public int Digits { get; set; } = 3;
- }
}
diff --git a/UICatalog/Scenarios/ContentScrolling.cs b/UICatalog/Scenarios/ContentScrolling.cs
index 5d4a1a3c2..9e4416658 100644
--- a/UICatalog/Scenarios/ContentScrolling.cs
+++ b/UICatalog/Scenarios/ContentScrolling.cs
@@ -229,7 +229,7 @@ public class ContentScrolling : Scenario
Y = Pos.Bottom (cbAllowYGreaterThanContentHeight)
};
- Buttons.NumericUpDown contentSizeWidth = new Buttons.NumericUpDown
+ NumericUpDown contentSizeWidth = new NumericUpDown
{
Value = view.GetContentSize ().Width,
X = Pos.Right (labelContentSize) + 1,
@@ -256,7 +256,7 @@ public class ContentScrolling : Scenario
Y = Pos.Top (labelContentSize)
};
- Buttons.NumericUpDown contentSizeHeight = new Buttons.NumericUpDown
+ NumericUpDown contentSizeHeight = new NumericUpDown
{
Value = view.GetContentSize ().Height,
X = Pos.Right (labelComma) + 1,
diff --git a/UICatalog/Scenarios/NumericUpDownDemo.cs b/UICatalog/Scenarios/NumericUpDownDemo.cs
new file mode 100644
index 000000000..b514a041a
--- /dev/null
+++ b/UICatalog/Scenarios/NumericUpDownDemo.cs
@@ -0,0 +1,291 @@
+#nullable enable
+using System;
+using Terminal.Gui;
+
+namespace UICatalog.Scenarios;
+
+[ScenarioMetadata ("NumericUpDown", "Demonstrates the NumericUpDown View")]
+[ScenarioCategory ("Controls")]
+public class NumericUpDownDemo : Scenario
+{
+ public override void Main ()
+ {
+ Application.Init ();
+
+ Window app = new ()
+ {
+ Title = GetQuitKeyAndName (),
+ TabStop = TabBehavior.TabGroup
+ };
+
+ var editor = new AdornmentsEditor
+ {
+ X = 0,
+ Y = 0,
+ AutoSelectViewToEdit = true,
+ TabStop = TabBehavior.NoStop
+ };
+ app.Add (editor);
+
+ NumericUpDownEditor intEditor = new ()
+ {
+ X = Pos.Right (editor),
+ Y = 0,
+ Title = "int",
+ };
+
+ app.Add (intEditor);
+
+ NumericUpDownEditor floatEditor = new ()
+ {
+ X = Pos.Right (intEditor),
+ Y = 0,
+ Title = "float",
+ };
+ app.Add (floatEditor);
+
+ app.Initialized += AppInitialized;
+
+ void AppInitialized (object? sender, EventArgs e)
+ {
+ floatEditor!.NumericUpDown!.Increment = 0.1F;
+ floatEditor!.NumericUpDown!.Format = "{0:0.0}";
+
+ }
+
+ Application.Run (app);
+ app.Dispose ();
+ Application.Shutdown ();
+
+ }
+
+}
+
+internal class NumericUpDownEditor : View where T : notnull
+{
+ private NumericUpDown? _numericUpDown;
+
+ internal NumericUpDown? NumericUpDown
+ {
+ get => _numericUpDown;
+ set
+ {
+ if (value == _numericUpDown)
+ {
+ return;
+ }
+ _numericUpDown = value;
+
+ if (_numericUpDown is { } && _value is { })
+ {
+ _value.Text = _numericUpDown.Text;
+ }
+ }
+ }
+
+ private TextField? _value;
+ private TextField? _format;
+ private TextField? _increment;
+
+ internal NumericUpDownEditor ()
+ {
+ _numericUpDown = null;
+ Title = "NumericUpDownEditor";
+ BorderStyle = LineStyle.Single;
+ Width = Dim.Auto (DimAutoStyle.Content);
+ Height = Dim.Auto (DimAutoStyle.Content);
+ TabStop = TabBehavior.TabGroup;
+
+ Initialized += NumericUpDownEditorInitialized;
+
+ return;
+
+ void NumericUpDownEditorInitialized (object? sender, EventArgs e)
+ {
+ Label label = new ()
+ {
+ Title = "_Value: ",
+ Width = 12,
+ };
+ label.TextFormatter.Alignment = Alignment.End;
+ _value = new ()
+ {
+ X = Pos.Right (label),
+ Y = Pos.Top (label),
+ Width = 8,
+ Title = "Value",
+ };
+ _value.Accept += ValuedOnAccept;
+
+ void ValuedOnAccept (object? sender, EventArgs e)
+ {
+ if (_numericUpDown is null)
+ {
+ return;
+ }
+
+ try
+ {
+ if (string.IsNullOrEmpty (_value.Text))
+ {
+ // Handle empty or null text if needed
+ _numericUpDown.Value = default!;
+ }
+ else
+ {
+ // Parse _value.Text and then convert to type T
+ _numericUpDown.Value = (T)Convert.ChangeType (_value.Text, typeof (T));
+ }
+
+ _value.ColorScheme = SuperView.ColorScheme;
+
+ }
+ catch (System.FormatException)
+ {
+ _value.ColorScheme = Colors.ColorSchemes ["Error"];
+ }
+ catch (InvalidCastException)
+ {
+ _value.ColorScheme = Colors.ColorSchemes ["Error"];
+ }
+ finally
+ {
+ }
+
+ }
+ Add (label, _value);
+
+ label = new ()
+ {
+ Y = Pos.Bottom (_value),
+ Width = 12,
+ Title = "_Format: ",
+ };
+ label.TextFormatter.Alignment = Alignment.End;
+
+ _format = new ()
+ {
+ X = Pos.Right (label),
+ Y = Pos.Top (label),
+ Title = "Format",
+ Width = Dim.Width (_value),
+ };
+ _format.Accept += FormatOnAccept;
+
+ void FormatOnAccept (object? o, EventArgs eventArgs)
+ {
+ if (_numericUpDown is null)
+ {
+ return;
+ }
+
+ try
+ {
+ // Test format to ensure it's valid
+ _ = string.Format (_format.Text, _value);
+ _numericUpDown.Format = _format.Text;
+
+ _format.ColorScheme = SuperView.ColorScheme;
+
+ }
+ catch (System.FormatException)
+ {
+ _format.ColorScheme = Colors.ColorSchemes ["Error"];
+ }
+ catch (InvalidCastException)
+ {
+ _format.ColorScheme = Colors.ColorSchemes ["Error"];
+ }
+ finally
+ {
+ }
+ }
+
+ Add (label, _format);
+
+ label = new ()
+ {
+ Y = Pos.Bottom (_format),
+ Width = 12,
+ Title = "_Increment: ",
+ };
+ label.TextFormatter.Alignment = Alignment.End;
+ _increment = new ()
+ {
+ X = Pos.Right (label),
+ Y = Pos.Top (label),
+ Title = "Increment",
+ Width = Dim.Width (_value),
+ };
+
+ _increment.Accept += IncrementOnAccept;
+
+ void IncrementOnAccept (object? o, EventArgs eventArgs)
+ {
+ if (_numericUpDown is null)
+ {
+ return;
+ }
+
+ try
+ {
+ if (string.IsNullOrEmpty (_value.Text))
+ {
+ // Handle empty or null text if needed
+ _numericUpDown.Increment = default!;
+ }
+ else
+ {
+ // Parse _value.Text and then convert to type T
+ _numericUpDown.Increment = (T)Convert.ChangeType (_increment.Text, typeof (T));
+ }
+
+ _increment.ColorScheme = SuperView.ColorScheme;
+
+ }
+ catch (System.FormatException)
+ {
+ _increment.ColorScheme = Colors.ColorSchemes ["Error"];
+ }
+ catch (InvalidCastException)
+ {
+ _increment.ColorScheme = Colors.ColorSchemes ["Error"];
+ }
+ finally
+ {
+ }
+ }
+
+ Add (label, _increment);
+
+ _numericUpDown = new ()
+ {
+ X = Pos.Center (),
+ Y = Pos.Bottom (_increment) + 1,
+ Increment = (dynamic)1,
+ };
+
+ _numericUpDown.ValueChanged += NumericUpDownOnValueChanged;
+
+ void NumericUpDownOnValueChanged (object? o, EventArgs eventArgs)
+ {
+ _value.Text = _numericUpDown.Text;
+ }
+
+ _numericUpDown.IncrementChanged += NumericUpDownOnIncrementChanged;
+
+ void NumericUpDownOnIncrementChanged (object? o, EventArgs eventArgs)
+ {
+ _increment.Text = _numericUpDown.Increment.ToString ();
+ }
+
+ Add (_numericUpDown);
+
+ _value.Text = _numericUpDown.Text;
+ _format.Text = _numericUpDown.Format;
+ _increment.Text = _numericUpDown.Increment.ToString ();
+ }
+ }
+
+
+}
diff --git a/UICatalog/Scenarios/PosAlignDemo.cs b/UICatalog/Scenarios/PosAlignDemo.cs
index d7ae5146e..03e90b806 100644
--- a/UICatalog/Scenarios/PosAlignDemo.cs
+++ b/UICatalog/Scenarios/PosAlignDemo.cs
@@ -236,7 +236,7 @@ public sealed class PosAlignDemo : Scenario
}
];
- Buttons.NumericUpDown addedViewsUpDown = new()
+ NumericUpDown addedViewsUpDown = new()
{
Width = 9,
Title = "Added",
diff --git a/UICatalog/Scenarios/Sliders.cs b/UICatalog/Scenarios/Sliders.cs
index 37d97c467..40e98dd33 100644
--- a/UICatalog/Scenarios/Sliders.cs
+++ b/UICatalog/Scenarios/Sliders.cs
@@ -407,7 +407,7 @@ public class Sliders : Scenario
Text = "Min _Inner Spacing:",
};
- Buttons.NumericUpDown innerSpacingUpDown = new ()
+ NumericUpDown innerSpacingUpDown = new ()
{
X = Pos.Right (label) + 1
};
diff --git a/UnitTests/Views/NumericUpDownTests.cs b/UnitTests/Views/NumericUpDownTests.cs
new file mode 100644
index 000000000..916053001
--- /dev/null
+++ b/UnitTests/Views/NumericUpDownTests.cs
@@ -0,0 +1,238 @@
+using System.Globalization;
+using Xunit.Abstractions;
+
+namespace Terminal.Gui.ViewsTests;
+
+public class NumericUpDownTests (ITestOutputHelper _output)
+{
+ [Fact]
+ public void WhenCreated_ShouldHaveDefaultValues_int ()
+ {
+ NumericUpDown numericUpDown = new ();
+
+ Assert.Equal (0, numericUpDown.Value);
+ Assert.Equal (1, numericUpDown.Increment);
+ }
+
+ [Fact]
+ public void WhenCreated_ShouldHaveDefaultValues_long ()
+ {
+ NumericUpDown numericUpDown = new ();
+
+ Assert.Equal (0, numericUpDown.Value);
+ Assert.Equal (1, numericUpDown.Increment);
+ }
+
+ [Fact]
+ public void WhenCreated_ShouldHaveDefaultValues_float ()
+ {
+ NumericUpDown numericUpDown = new ();
+
+ Assert.Equal (0F, numericUpDown.Value);
+ Assert.Equal (1.0F, numericUpDown.Increment);
+ }
+
+ [Fact]
+ public void WhenCreated_ShouldHaveDefaultValues_double ()
+ {
+ NumericUpDown numericUpDown = new ();
+
+ Assert.Equal (0F, numericUpDown.Value);
+ Assert.Equal (1.0F, numericUpDown.Increment);
+ }
+
+ [Fact]
+ public void WhenCreated_ShouldHaveDefaultValues_decimal ()
+ {
+ NumericUpDown numericUpDown = new ();
+
+ Assert.Equal (0, numericUpDown.Value);
+ Assert.Equal (1, numericUpDown.Increment);
+ }
+
+ [Fact]
+ public void WhenCreatedWithCustomValues_ShouldHaveCustomValues_int ()
+ {
+ NumericUpDown numericUpDown = new()
+ {
+ Value = 10,
+ Increment = 2
+ };
+
+ Assert.Equal (10, numericUpDown.Value);
+ Assert.Equal (2, numericUpDown.Increment);
+ }
+
+ [Fact]
+ public void WhenCreatedWithCustomValues_ShouldHaveCustomValues_float ()
+ {
+ NumericUpDown numericUpDown = new()
+ {
+ Value = 10.5F,
+ Increment = 2.5F
+ };
+
+ Assert.Equal (10.5F, numericUpDown.Value);
+ Assert.Equal (2.5F, numericUpDown.Increment);
+ }
+
+ [Fact]
+ public void WhenCreatedWithCustomValues_ShouldHaveCustomValues_decimal ()
+ {
+ NumericUpDown numericUpDown = new ()
+ {
+ Value = 10.5m,
+ Increment = 2.5m
+ };
+
+ Assert.Equal (10.5m, numericUpDown.Value);
+ Assert.Equal (2.5m, numericUpDown.Increment);
+ }
+
+ [Fact]
+ public void WhenCreatedWithInvalidType_ShouldThrowInvalidOperationException ()
+ {
+ Assert.Throws (() => new NumericUpDown ());
+ }
+
+ [Fact]
+ public void WhenCreatedWithInvalidTypeObject_ShouldNotThrowInvalidOperationException ()
+ {
+ NumericUpDown