Overview

Namespace: TheTechIdea.Beep.Winform.Controls.Numerics

Assembly: TheTechIdea.Beep.Winform.Controls

Inheritance: BeepNumericUpDown → BaseControl → UserControl

Implements: IBeepComponent

BeepNumericUpDown is a feature-rich numeric input control for business applications. It combines a themable spin-button interface with 20+ NumericStyle presets, four display modes (Standard, Percentage, Currency, ProgressValue), 30+ input mask presets (phone, SSN, credit card, ISBN, GPS coordinates, etc.), and a comprehensive multi-stage validation pipeline with 13 dedicated events.

It uses a pluggable painter system for layout and rendering, and supports both inline TextBox editing and mouse/keyboard increment/decrement with auto-repeat acceleration. The control is split across five partial class files for maintainability.

Key Features

  • 20+ Numeric Styles: Standard, CompactStepper, Slider, Currency, Percentage, Phone, Decimal, Integer, Rating, Progress, Time, Scientific, Dial, VerticalStepper, Calculator, Temperature, Inline, TouchOptimized, Display, Chip.
  • Pluggable Painter System: INumericUpDownPainter implementations (StandardNumericPainter, CompactStepperPainter, CurrencyPainter, PhoneNumberPainter, InlineStepperPainter) with hit-area management and layout.
  • Four Display Modes: Standard, Percentage (auto %), Currency (auto $+decimals), CustomUnit (prefix+suffix+unit), ProgressValue (% with min/max/increment presets).
  • 30+ Mask Presets: PhoneUS, PhoneInternational, SSN, CreditCard, ZipCode/Plus4, Currency, Percentage, Time24/12Hour, Date formats, IPAddress, MACAddress, Decimal2/4Places, IntegerWithCommas, AccountNumber, RoutingNumber, EIN, ISBN10/13, ProductCode, Latitude, Longitude, WeightKg/Lbs, TemperatureC/F, DistanceKm/Miles, FileSizeMB/GB, Scientific, Hex, Binary, Custom.
  • 13-Event Validation Pipeline: ValueValidating (basic + extended), ValueValidated, RangeExceeded, InvalidInput, FormatValidation, StepValidationFailed, MinimumReached, MaximumReached, plus per-char and per-value comprehensive helpers.
  • Keyboard Navigation: Arrow Up/Down, PageUp/PageDown (10×step), Home/End (min/max), Enter/Escape commit/cancel, mouse wheel, configurable arrow-key interception.
  • Auto-Repeat Acceleration: 500ms initial delay, 50ms repeat, accelerates after 5 repeats. Direction tracked via _repeatIncrementDirection.
  • Inline TextBox Editing: Transparent overlay for direct typing with SelectAllOnFocus, invalid-input highlighting (red background), and prefix/suffix stripping on commit.
  • Percentage Auto-Calc: SetPercentageValue(part, total), GetActualValue() computes from TotalValue when AutoCalculateFromTotal is true.
  • Value Wrapping: WrapValues wraps max→min and min→max on increment/decrement.
  • Accessibility: AccessibleRole=SpinButton, configurable AccessibleName/Description.

Display Modes (NumericUpDownDisplayMode)

ModeDescriptionAuto-Config
StandardPlain numeric with optional prefix/suffix.No auto-formatting.
Percentage0-100 range with %.Suffix="%", Decimals=0, range 0-100.
CurrencyMonetary with symbol.Prefix="$", Decimals=2, ThousandsSep=true.
CustomUnitCustom prefix/suffix/unit.Format: {Prefix}{Value}{Suffix} {Unit}.
ProgressValueProgress percentage.Suffix="%", min=0, max=100, Decimals=0, Increment=1.

Numeric Styles (NumericStyle Enum — 22 values)

StylePainterAuto-Applied Settings
StandardStandardNumericPainterDefault side-button layout.
CompactStepperCompactStepperPainterCompact right-side only buttons.
Slider(Standard)Spin buttons hidden. Future: draggable slider.
CurrencyCurrencyPainterMode=Currency, Decimals=2, Thousands=true.
PercentageCompactStepperPainterMode=Percentage, min=0, max=100, Decimals=1.
PhonePhoneNumberPainterDecimals=0, AllowNegative=false, min=0.
DecimalCompactStepperPainterDecimalPlaces=2.
IntegerCompactStepperPainterDecimalPlaces=0.
Rating(Standard)min=0, max=5, Increment=1, Decimals=0.
Progress(Standard)min=0, max=100, Mode=Percentage, ReadOnly=true.
Time(Standard)Future: time input.
Scientific(Standard)DecimalPlaces=4.
Dial(Standard)Buttons hidden. Future: circular dial.
VerticalStepperStandardNumericPainterVertical button layout.
Calculator(Standard)Future: calculator-style pad.
Temperature(Standard)Decimals=1, Suffix="°C".
InlineInlineStepperPainterNo buttons; inline edit only.
TouchOptimized(Standard)Future: large touch buttons.
Display(Standard)Read-only; no buttons.
Chip(Standard)Future: chip/tag style.

Mask Presets (NumericMaskPreset — 37 values)

PresetPatternMaxLenDecimalsIcon
None—50——
PhoneUS(###) ###-####140Phone
PhoneInternational+## (###) ###-####180Phone
SSN###-##-####110Id
CreditCard#### #### #### ####190CreditCard
ZipCode#####50MapPin
ZipCodePlus4#####-####100MapPin
Currency$#,###.##502CashBanknote
Percentage##.##%502Percentage
Time24Hour##:##50Clock
Time12Hour##:## AM80Clock
DateMMDDYYYY##/##/####100Calendar
DateYYYYMMDD####-##-##100Calendar
IPAddress###.###.###.###150Globe
MACAddress##:##:##:##:##:##170Hash
Decimal2Places#,###.##502Hash
Decimal4Places#,###.####504Hash
IntegerWithCommas#,###500Hash
AccountNumber####-####-####140CreditCard
RoutingNumber#########90BldgTower
EIN##-#######100BldgTower
ISBN10#-###-#####-#130Hash
ISBN13###-#-###-#####-#170Hash
ProductCode###-###-###110Package
Latitude##.######506MapPin
Longitude###.######506MapPin
WeightKg#,###.##502Weight
WeightLbs#,###.##502Weight
TemperatureCelsius###.#501Temperature
TemperatureFahrenheit###.#501Temperature
DistanceKm#,###.##502Navigation
DistanceMiles#,###.##502Navigation
FileSizeMB#,###.##502Desktop
FileSizeGB#,###.##502Desktop
Scientific#.####E+##504AtomN2
Hexadecimal0x########100Hash
Binary0b########100Hash

Use Custom with CustomMask for user-defined patterns (e.g. "####-####").

Properties (29 total)

PropertyTypeDefaultCategoryDescription
MinimumValuedecimal0mNumeric SettingsMinimum allowed value. Clamps Value if set below.
MaximumValuedecimal100mNumeric SettingsMaximum allowed value. Clamps Value if set above.
IncrementValuedecimal1mNumeric SettingsStep for spin buttons, arrow keys, wheel.
Valuedecimal0mNumeric SettingsCurrent value. Triggers validate + ValueValidating + ValueChanged + boundary events.
DecimalPlacesint0FormatDecimal places (0-15). Affects display formatting and input validation.
DisplayModeNumericUpDownDisplayModeStandardFormatDisplay: Standard, Percentage, Currency, CustomUnit, ProgressValue. Auto-configures prefix/suffix.
NumericStyleNumericStyleStandardAppearanceVisual/interaction style. Triggers ConfigureForNumericStyle() and InitializePainter().
Prefixstring""FormatString prepended to displayed value (e.g. "$", "£").
Suffixstring""FormatString appended to displayed value (e.g. "%", "kg").
Unitstring""FormatUnit label in CustomUnit mode.
ThousandsSeparatorboolfalseFormatDisplay thousands commas (e.g. 1,234,567).
ReadOnlyboolfalseBehaviorPrevent user changes. Sets TextBox.ReadOnly on overlay.
InterceptArrowKeysbooltrueBehaviorUp/Down adjust value vs. navigate focus.
AllowNegativebooltrueBehaviorProhibit negatives. Forces MinimumValue to 0.
UseThemeColorsbooltrueAppearanceDerive colours from theme via NumericThemeHelpers.
WrapValuesboolfalseBehaviorIncrement past max wraps to min; decrement past min wraps to max.
SelectAllOnFocusbooltrueBehaviorSelect entire text on GotFocus.
ButtonSizeNumericSpinButtonSizeStandardAppearanceSmall (20), Standard (24), Large (28), ExtraLarge (32).
ShowSpinButtonsbooltrueAppearanceHide buttons for inline-only editing.
IsPercentageModeboolfalseBusinessShortcut: Mode=Percentage, min=0, max=100, Decimals=0.
AutoCalculateFromTotalboolfalseBusinessGetActualValue() = Value/100 * TotalValue when true in % mode.
EnableShadowboolfalseAppearanceSubtle shadow around control.
AccessibilityNamestring""AccessibilityScreen-reader name. Maps to AccessibleName.
AccessibilityDescriptionstring""AccessibilityInput guidance. Maps to AccessibleDescription.
TotalValuedecimal0mBusinessTotal used when AutoCalculateFromTotal=true.
MaskPresetNumericMaskPresetNoneFormatPredefined mask. Triggers ApplyMaskPreset().
CustomMaskstring""FormatCustom pattern when MaskPreset=Custom. # for digits.
MaskConfigNumericMaskConfig?null—Read-only resolved mask config.
CurrentPainterINumericUpDownPainter(resolved)—Read-only active painter.

Methods

MethodVisibilitySignatureDescription
PerformSteppublicvoid PerformStep()Increments Value by IncrementValue.
ConfigureForPercentagepublicvoid ConfigureForPercentage()Mode=ProgressValue, IsPercentageMode=true.
ConfigureForCurrencypublicvoid ConfigureForCurrency(string symbol="$")Mode=Currency, Prefix, Decimals=2, Thousands=true.
ConfigureForTaskProgresspublicvoid ConfigureForTaskProgress()Mode=ProgressValue, min=0, max=100, Increment=5, PercentageMode.
SetPercentageValuepublicvoid SetPercentageValue(decimal part, decimal total)Sets Value = Math.Round(part/total*100).
GetActualValuepublicdecimal GetActualValue()% mode: Value/100*TotalValue. Else: Value.
SetValuepublicvoid SetValue(object value)Sets Value from decimal or string. IBeepComponent.
GetValuepublicobject GetValue()Returns Value as object.
ApplyThemepublicvoid ApplyTheme()Applies Back/Fore/Border/Hover colours, TextBox theme, error colour via NumericThemeHelpers.
GetMaskIconPathpublicstring GetMaskIconPath()Returns icon path from current mask config.
ShouldShowMaskIconpublicbool ShouldShowMaskIcon()True when mask config has ShowIcon=true and non-empty IconPath.
ValidateRangepublicbool ValidateRange(decimal, out string)Check value ∈ [Min, Max]. Raises RangeExceeded on failure.
ValidateFormatpublicbool ValidateFormat(string, out string)Check input parses as decimal and matches mask. Raises InvalidInput/FormatValidation.
ValidateSteppublicbool ValidateStep(decimal, out string)Check (value-Min) % Increment == 0. Raises StepValidationFailed.
ValidateNumericInputpublicbool ValidateNumericInput(char, string, int)Per-char: reject non-digits, dup decimals, misplaced minus.
ValidateDecimalPlacespublicbool ValidateDecimalPlaces(string, out string)Check decimal places ≤ DecimalPlaces. Raises FormatValidation.
ValidateValuepublicbool ValidateValue(decimal, out string)Full validation: range+step+ValueValidating+ValueValidatingEx+ValueValidated.

Events (13 total)

EventArgs TypeFire PointDescription
ValueChangedEventHandlerAfter range clamp, before boundary checksValue property changed.
ValueValidatingValueValidatingEventArgsBefore Value change committedCancel via e.Cancel. OldValue/NewValue provided.
MinimumReachedEventHandlerValue == MinimumValue after changeFloor boundary hit.
MaximumReachedEventHandlerValue == MaximumValue after changeCeiling boundary hit.
UpButtonClickedEventHandlerIncrementValueInternal calledUp/increment action triggered.
DownButtonClickedEventHandlerDecrementValueInternal calledDown/decrement action triggered.
ValueValidationFailedEventHandlerValueValidating cancelledBasic validation rejected.
ValueValidatingExNumericValueValidatingEventArgsExtended validationOldValue, NewValue, Cancel, ValidationMessage.
ValueValidatedNumericValueValidatedEventArgsAfter validation passesOldValue, NewValue, IsValid, ValidationMessage.
RangeExceededRangeExceededEventArgsValidateRange failsAttemptedValue, Min/Max, IsMaximumExceeded.
InvalidInputInvalidInputEventArgsParse/mask validation failsInput string and Reason.
FormatValidationFormatValidationEventArgsFormat check occursInput, IsValid, ExpectedFormat.
StepValidationFailedEventArgsValidateStep failsValue not a multiple of IncrementValue.

Validation Pipeline

The Value setter executes the following validation sequence:

  1. Range Clamp: ValidateValueRange(newValue) — clamps or wraps value to [Min, Max].
  2. Equality Check: Skip if old == new.
  3. Basic Validation: ValueValidating?.Invoke(this, args) — user can cancel. On cancel: ValueValidationFailed fires, setter returns.
  4. Value Commit: _value = newValue.
  5. Change Notification: ValueChanged fires.
  6. Boundary Events: MinimumReached / MaximumReached if at boundary.
  7. Invalidation: Invalidate() triggers repaint.

Programmatic validation is available through public methods: ValidateRange, ValidateFormat, ValidateStep, ValidateNumericInput, ValidateDecimalPlaces, and the comprehensive ValidateValue which chains range+step+ValueValidating+ValueValidatingEx+ValueValidated.

Theming

BeepNumericUpDown uses dedicated theme helpers under Numerics.Helpers:

  • NumericThemeHelpers.GetNumericBackgroundColor(theme, useTheme, isHovered) — background.
  • NumericThemeHelpers.GetNumericTextColor(theme, useTheme, isHovered) — foreground.
  • NumericThemeHelpers.GetNumericBorderColor(theme, useTheme, isHovered) — border.
  • NumericThemeHelpers.GetErrorColor(theme, useTheme) — invalid-input background.
  • NumericFontHelpers.GetNumericFont(controlStyle) — font for TextBox overlay.

ApplyTheme() updates BackColor, ForeColor, BorderColor, HoverBackColor, HoverForeColor, HoverBorderColor, and the internal TextBox's BackColor, ForeColor, and Font. BeepStyling handles background, border, and shadow at the BaseControl level.

Examples

Basic Numeric

var n = new BeepNumericUpDown { Min=0, Max=100, Increment=5, Value=50, Decimals=1, Width=150 };
n.ValueChanged += (s, e) => Console.WriteLine($"New: {n.Value}");

Phone with Mask

var phone = new BeepNumericUpDown { MaskPreset = NumericMaskPreset.PhoneUS, NumericStyle = NumericStyle.Phone, Width = 200 };

Currency with Validation

var cur = new BeepNumericUpDown(); cur.ConfigureForCurrency("£");
cur.Min=0; cur.Max=1000000;
cur.ValueValidating += (s, e) => { if (e.NewValue > 50000) e.Cancel = true; };

Percentage Auto-Calc

var pct = new BeepNumericUpDown { IsPercentageMode=true, AutoCalculateFromTotal=true, TotalValue=1000m };
pct.Value = 25; decimal actual = pct.GetActualValue(); // 250.0

Bulk Configuration

new BeepNumericUpDown().ConfigureForPercentage();
new BeepNumericUpDown().ConfigureForTaskProgress();
new BeepNumericUpDown().ConfigureForCurrency("€");

Wrap Values

var w = new BeepNumericUpDown { Min=0, Max=10, WrapValues=true, Value=10 };
w.PerformStep(); // wraps to 0

GPS Latitude

var lat = new BeepNumericUpDown { MaskPreset = NumericMaskPreset.Latitude, Width = 180 };
// Auto: Decimals=6, min=-90, max=90

Architecture

FileLinesResponsibility
BeepNumericUpDown.cs~722Main: fields (29 private), properties (29), events (13), constructor (sets ControlStyles, BorderRadius, initialises), display mode config, ValidateValueRange, public methods (PerformStep, ConfigureFor*, SetPercentageValue, GetActualValue, SetValue, GetValue, ApplyTheme, Dispose), ValueValidatingEventArgs.
BeepNumericUpDown.Drawing.cs~189Rendering: DrawContent, Draw, Paint (BeepStyling background+border+painter layout+text+button icons), PaintButtonBackgrounds, GetControlPath, OnResize, CalculateButtonAreas, GetButtonWidthForSize.
BeepNumericUpDown.Events.cs~252Input: OnMouseMove (hover tracking), OnMouseLeave, OnMouseDown (button press + repeat start + edit start), OnMouseUp (release + stop repeat), OnMouseClick (hit area), OnMouseDoubleClick (edit start), OnMouseWheel, OnKeyDown (arrows/PgUp/PgDn/Home/End/Enter/Escape), ProcessDialogKey, OnGotFocus (SelectAll), OnLostFocus (EndEditing), OnEnabledChanged, StartRepeatTimer/StopRepeatTimer/RepeatTimer_Tick.
BeepNumericUpDown.Painters.cs~183Painters: InitializePainter (maps NumericStyle to painters: CompactStepper, Inline, Currency, Phone, Standard fallback), RefreshHitAreas, UpdateButtonHoverState, HandleHitAreaClick, NumericUpDownPainterContext adapter (exposes Value, Min, Max, Increment, Decimals, state, buttons, layout, display, theme, actions to painters).
BeepNumericUpDown.Helpers.cs~610Helpers: IncrementValueInternal/DecrementValueInternal (wrap-aware, fires Up/DownButtonClicked), FormatValue (decimals+thousands+display mode), UpdateDisplayText, ConfigureForNumericStyle (all 22 styles), TextBox management (StartEditing: create+position+focus+selectall, EndEditing: parse+validate+highlight+events), mask preset (ApplyMaskPreset, CreateCustomMaskConfig, GetMaskIconPath, ShouldShowMaskIcon), validation (ValidateRange, ValidateFormat, ValidateStep, ValidateNumericInput, ValidateDecimalPlaces, ValidateValue).
NumericStyle.cs~133Enum: 22 NumericStyle values with DescriptionAttributes.
NumericMaskPreset.cs~449Enum: 37 mask presets + NumericMaskConfig class with FromPreset factory (MaskPattern, MaxLength, DecimalPlaces, AllowNegative, Min/Max, IconPath, Unit, ShowIcon).
Painters/INumericUpDownPainter.cs~30Interface: CalculateLayout, FormatValue, PaintValueText, PaintButtonIcons, UpdateHitAreas.
Painters/StandardNumericPainter.cs~100Default: side buttons, standard layout.
Painters/CompactStepperPainter.cs~80Compact: right-side only.
Painters/CurrencyPainter.cs~80Currency: symbol placement, formatted display.
Painters/PhoneNumberPainter.cs~80Phone: formatted display with mask.
Painters/InlineStepperPainter.cs~80Inline: no buttons.
Painters/BaseModernNumericPainter.cs~60Abstract base for modern-style painters.
Helpers/NumericThemeHelpers.cs~60Colour resolution.
Helpers/NumericFontHelpers.cs~30Font resolution.
Helpers/NumericStyleHelpers.cs~40Style metrics.
Helpers/NumericIconHelpers.cs~30Icon defaults.

Inline TextBox Editing

The control uses a transparent TextBox overlay (_textBox) for direct numeric entry. Key behaviours:

  • Creation: Lazily created in StartEditing() with BorderStyle=None, theme-derived BackColor/ForeColor, and font from NumericFontHelpers.
  • Positioning: Centred vertically, inset by padding, accounting for both left and right spin-button widths when visible.
  • Focus Behaviour: SelectAllOnFocus selects all text. OnLostFocus calls EndEditing(true) to commit.
  • Commit: EndEditing(true) strips prefix/suffix/unit symbols and percent signs, parses via decimal.TryParse. On failure, highlights via _invalidInputColor and fires InvalidInput + ValueValidationFailed.
  • Cancel: EndEditing(false) (Escape key) discards the edit and hides the TextBox without changing Value.

Auto-Repeat System

When a spin button is held down, StartRepeatTimer fires an immediate action, then uses a System.Windows.Forms.Timer with the following progression:

  • Initial delay: 500ms (INITIAL_DELAY)
  • Repeat interval: 50ms (REPEAT_DELAY)
  • Acceleration: After 5 repeats, maintains 50ms interval (can reach 10ms theoretical MAX_REPEAT_SPEED)
  • Direction: Tracked via _repeatIncrementDirection (true=up, false=down)
  • Cleanup: StopRepeatTimer on MouseUp, OnEnabledChanged(false), or Dispose