﻿Imports System.Globalization

Public Class SimpleNumberBox
    Inherits System.Windows.Forms.TextBox

    Private Const WM_PASTE As Integer = &H302

    Protected Overrides Sub OnKeyPress(ByVal e As System.Windows.Forms.KeyPressEventArgs)
        Dim keyChar = e.KeyChar
        Dim formatInfo = NumberFormatInfo.CurrentInfo

        If Char.IsControl(keyChar) OrElse _
           Char.IsDigit(keyChar) OrElse _
           ((keyChar = formatInfo.NegativeSign OrElse _
             keyChar = formatInfo.NumberDecimalSeparator) AndAlso _
            Me.ValidateText(keyChar)) Then
            MyBase.OnKeyPress(e)
        Else
            e.Handled = True
        End If
    End Sub

    Protected Overrides Sub OnValidated(ByVal e As System.EventArgs)
        If Not Decimal.TryParse(Me.Text, New Decimal) Then
            Me.Clear()
        End If

        MyBase.OnValidated(e)
    End Sub

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        If m.Msg <> WM_PASTE OrElse _
           Not Clipboard.ContainsText() OrElse _
           Me.ValidateText(Clipboard.GetText()) Then
            MyBase.WndProc(m)
        End If
    End Sub

    Private Function ValidateText(ByVal newText As String) As Boolean
        Dim isValid = True
        Dim currentText = Me.Text
        Dim selectionStart = Me.SelectionStart
        Dim proposedText = currentText.Substring(0, selectionStart) & _
                           newText & _
                           currentText.Substring(selectionStart + Me.SelectionLength)

        If Not Decimal.TryParse(proposedText, _
                                NumberStyles.AllowLeadingSign Or NumberStyles.AllowDecimalPoint, _
                                Nothing, _
                                New Decimal) Then
            Dim formatInfo = NumberFormatInfo.CurrentInfo
            Dim negativeSign = formatInfo.NegativeSign
            Dim decimalSeparator = formatInfo.NumberDecimalSeparator

            isValid = (proposedText = negativeSign) OrElse _
                      (proposedText = decimalSeparator) OrElse _
                      (proposedText = negativeSign & decimalSeparator)
        End If

        Return isValid
    End Function

End Class
