Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
OnKeyPress and paste
Message
General information
Forum:
ASP.NET
Category:
Forms
Miscellaneous
Thread ID:
00992739
Message ID:
00992747
Views:
26
In VB.Net, I convert the KeyChar to integer and CTRL-V has a value of 22. But be careful because you also have to handle the context menu that also has a Paste item. You better handle the WndProc methods.

Here is my latest implementation of my complete numeric textbox. If you find anything, please tell me.
Option Strict On

'=====================================================================================
' Classe        :   NumericTextbox.vb
'
' Auteur        :   Eric Moreau
'
' Description   :   System.Windows.Forms.TextBox Extender
'
' Utilisation   :   1. Add a regular TextBox to your form
'                   2. In the " Windows Form Designer generated code " section, 
'                      replace System.Windows.Forms.TextBox by NumericTextBox (2 places) 
'
' Historique    :
' Auteur            Date            Intervention
' ----------------- --------------- -------------------------------------------------
' Eric Moreau       2003/10/25      Création
'=====================================================================================

Imports System.ComponentModel

Public Class NumericTextBox
    Inherits System.Windows.Forms.TextBox

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call
        CustomInitialization()
    End Sub

    'UserControl overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    Friend WithEvents ErrorProvider1 As System.Windows.Forms.ErrorProvider
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.ErrorProvider1 = New System.Windows.Forms.ErrorProvider
        '
        'S2iNumericTextBox
        '

    End Sub

#End Region

#Region " Members "

    Private mblnErrorProviderVisible As Boolean
    Private mbytNumberDecimals As Byte
    Private mbytNumberDigits As Byte
	Private mdecDefaultValue As Decimal
	Private mdecValueMax As Decimal
	Private mdecValueMin As Decimal
    Private mintErrorLanguage As enuLangueMessage
    Private mstrDisplayFormat As String

    Public Event ValidationError(ByVal sender As Object, ByVal e As NumericTBEventArgs)

    Enum enuErrors
        ErrNone
        ErrTooManyMinusSign
        ErrMinusSignMisplaced
        ErrNegativeNotAllowed
        ErrTooManyDot
        ErrDotNotAllowed
        ErrLessThenMin
        ErrGreaterThenMax
        ErrInvalidValue
        ErrInvalidChar
        ErrEmptyValue
        ErrTooManyDigits
        ErrTooManyDecimals
        ErrCannotApplyFormat
        ErrPasteCanceled
    End Enum

    Enum enuLangueMessage
        English
        Francais
    End Enum
#End Region '-- Members

#Region " Methods "

    Protected Overrides Sub CreateHandle()
		Me.Text = mdecDefaultValue.ToString
        MyBase.CreateHandle()
    End Sub

#Region " Public methods "

    '===========================================================================================================
    '=== Returns wheter the textbox content is valid or not
    '===========================================================================================================
    Public Function IsValid() As Boolean
        Return Me.ValidateFieldContent(Decimal.Parse(Me.Text, Globalization.NumberStyles.Any).ToString)
    End Function

#End Region '-- Public methods

#Region " Protected methods "
    <System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name:="FullTrust")> _
        Protected Overrides Sub WndProc(ByRef m As Message)

        Const WM_PASTE As Integer = &H302

        ' Listen for operating system messages
        Select Case m.Msg
            Case WM_PASTE
                Dim iData As IDataObject = Clipboard.GetDataObject()
                Dim s As String = CType(iData.GetData(DataFormats.Text), String)

                If Not s = Nothing Then
                    Dim strNewResult As String
                    Dim strBeginning As String = Me.Text.Substring(0, Me.SelectionStart)
                    Dim strEnding As String = Me.Text.Substring(Me.SelectionStart + Me.SelectionLength)
                    strNewResult = strBeginning & s & strEnding

                    If Me.ValidateFieldContent(strNewResult) Then
                        'OK - Resulting field will be OK
                        MyBase.WndProc(m)
                    Else
                        'The result of the paste would cause and invalid value so stop it
                        SetError(enuErrors.ErrPasteCanceled, strNewResult)
                    End If
                End If
            Case Else
                MyBase.WndProc(m)
        End Select
    End Sub

#End Region '-- Protected methods

#Region " Privates methods "

    '===========================================================================================================
    '=== Calculates the number of a given character into a string
    '===========================================================================================================
    Private Function CountChar(ByVal pstrSource As String, ByVal pstrChar As String) As Integer
        Return pstrSource.Length - pstrSource.Replace(pstrChar, "").Length
    End Function

    '===========================================================================================================
    '=== Custom initialization for the component
    '===========================================================================================================
    Private Sub CustomInitialization()
        Me.DisplayFormat = "###,##0.00"
        Me.ErrorMessageLanguage = enuLangueMessage.Francais
        Me.NumberDecimals = 2
        Me.NumberDigits = 6
		Me.ValueMax = 999999.99D
		Me.ValueMin = -999999.99D
    End Sub

    '===========================================================================================================
    '=== A centralized method to set the ErrorProvider control and to raise a custom event
    '===========================================================================================================
    Private Sub SetError(ByVal pError As enuErrors, Optional ByVal pstrValue As String = "")
        Dim strMessageE As String
        Dim strMessageF As String

        Select Case pError
            Case enuErrors.ErrNone
                strMessageE = ""
                strMessageF = ""
            Case enuErrors.ErrEmptyValue
                strMessageE = "Field cannot be left empty!"
                strMessageF = "La valeur ne peut pas être laissé vide!"
            Case enuErrors.ErrTooManyMinusSign
                strMessageE = "Only one minus sign is allowed!"
                strMessageF = "Un seul symbole négatif est permis!"
            Case enuErrors.ErrMinusSignMisplaced
                strMessageE = "The minus sign must be placed at the beginning!"
                strMessageF = "Le symbole négatif doit être placé au début!"
            Case enuErrors.ErrTooManyDot
                strMessageE = "Only one decimal separator is allowed!"
                strMessageF = "Un seul séparateur de décimales est permis!"
            Case enuErrors.ErrDotNotAllowed
                strMessageE = "Decimal separator is not allowed!"
                strMessageF = "Le séparateur de décimal n'est pas permis!"
            Case enuErrors.ErrTooManyDigits
                strMessageE = "Too many digits! Only " & Me.NumberDigits.ToString & " allowed."
                strMessageF = "Trop de chiffres! Seulement " & Me.NumberDigits.ToString & " sont permis."
            Case enuErrors.ErrTooManyDecimals
                strMessageE = "Too many decimals! Only " & Me.NumberDecimals.ToString & " allowed."
                strMessageF = "Trop de décimales! Seulement " & Me.NumberDecimals.ToString & " sont permis."
            Case enuErrors.ErrLessThenMin
                strMessageE = "Value is less then the minimum allowed (" & Me.ValueMin.ToString & ")!"
                strMessageF = "La valeur est inférieure au minimum permis (" & Me.ValueMin.ToString & ")!"
            Case enuErrors.ErrGreaterThenMax
                strMessageE = "Value is greater then the maximum allowed (" & Me.ValueMax.ToString & ")!"
                strMessageF = "La valeur est supérieure au maximum permis (" & Me.ValueMax.ToString & ")!"
            Case enuErrors.ErrNegativeNotAllowed
                strMessageE = "Negative Values not allowed!"
                strMessageF = "Les valeurs négatives ne sont pas permises!"
            Case enuErrors.ErrInvalidValue
                strMessageE = "The field does not allow this value! (" & pstrValue & ")"
                strMessageF = "Valeur invalide! (" & pstrValue & ")"
            Case enuErrors.ErrInvalidChar
                strMessageE = "Character not allowed!"
                strMessageF = "Caractère invalide!"
            Case enuErrors.ErrCannotApplyFormat
                strMessageE = "Cannot apply the display format!"
                strMessageF = "Impossible d'appliquer la propriété DisplayFormat!"
            Case enuErrors.ErrPasteCanceled
                strMessageE = "The paste operation was canceled because it would result in an invalid value (" & pstrValue & ")!"
                strMessageF = "L'opération >Coller< a été annulé parce qu'elle causerait une valeur invalide (" & pstrValue & ")!"
            Case Else
                strMessageE = "Unkown error!"
                strMessageF = "Erreur inconnue!"
        End Select

        If ErrorMessageLanguage = enuLangueMessage.English Then
            If mblnErrorProviderVisible Then ErrorProvider1.SetError(Me, strMessageE)
            If strMessageE.Length > 0 Then
                RaiseEvent ValidationError(Me, New NumericTBEventArgs(strMessageE, Me.Text))
            End If
        Else
            If mblnErrorProviderVisible Then ErrorProvider1.SetError(Me, strMessageF)
            If strMessageF.Length > 0 Then
                RaiseEvent ValidationError(Me, New NumericTBEventArgs(strMessageF, Me.Text))
            End If
        End If
    End Sub

    '===========================================================================================================
    '=== Validates many patters to be sure that the content of the field is valid.
    '=== Many of these validations cannot be done on the KeyPress event.
    '=== Others are also placed here to insure that paste or assignement is OK.
    '===========================================================================================================
    Private Function ValidateFieldContent(ByVal pstrText As String) As Boolean
        SetError(enuErrors.ErrNone)

        'Empty string not allowed
        If pstrText.Length = 0 Then
            SetError(enuErrors.ErrEmptyValue)
            Return False
        End If

        'Invalid string
		If Not Microsoft.VisualBasic.IsNumeric(pstrText) Then		'TODO replace the IsNumeric
			SetError(enuErrors.ErrInvalidValue)
			Return False
		Else
			'E.Moreau 2003/10/26 
			'Quand bindé sur un DECIMAL il retourne une valeur du style 123456.1200 ce qui cause une erreur si le champ ne peut contenir que 2 décimales!
			pstrText = Microsoft.VisualBasic.Val(pstrText).ToString		  'TODO replace the VAL
		End If

		'Check to see the number of minus sign(-) and its position
		Select Case CountChar(pstrText, "-")
			Case 0
				'OK No problems
			Case 1
				If Not pstrText.StartsWith("-") Then
					SetError(enuErrors.ErrMinusSignMisplaced)
					Return False
				End If
			Case Else
				SetError(enuErrors.ErrTooManyMinusSign)
				Return False
		End Select

		'Check to see if there is only one decimal separator
		Select Case CountChar(pstrText, System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator)
			Case 0
				'OK, No problems
			Case 1
				Dim intPos As Integer = pstrText.Replace("-", "").IndexOf(System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator)
				'Check if the number of digits to the left of the decimal separator is OK
				If intPos > Me.NumberDigits Then
					SetError(enuErrors.ErrTooManyDigits)
					Return False
				End If

				'Check if the number of digits to the right of the decimal separator is OK
				If pstrText.Replace("-", "").Length - (intPos + 1) > Me.NumberDecimals Then
					SetError(enuErrors.ErrTooManyDecimals)
					Return False
				End If
			Case Else
				SetError(enuErrors.ErrTooManyDot)
				Return False
		End Select

		'Check min and max values
		If Me.ValueMin <> 0 Or Me.ValueMax <> 0 Then
			If Microsoft.VisualBasic.Val(pstrText) < Me.ValueMin Then			 'TODO replace the VAL
				SetError(enuErrors.ErrLessThenMin)
				Return False
			End If
			If Microsoft.VisualBasic.Val(pstrText) > Me.ValueMax Then			 'TODO replace the VAL
				SetError(enuErrors.ErrGreaterThenMax)
				Return False
			End If
		End If

		'If we get through here, the value should be OK!!!
		Return True
    End Function

    '===========================================================================================================
    '=== Validates a single character (called by the KeyPress event).
    '===========================================================================================================
	Private Function ValidateKey() As Boolean
		Dim intPos As Integer = Me.Text.IndexOf(System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator)
		If intPos = -1 Then
			If Me.Text.Replace("-", "").Length = Me.NumberDigits Then
				SetError(enuErrors.ErrTooManyDigits)
				Return False
			End If
		Else
			If Me.SelectionStart > intPos Then
				'Check if the number of digits to the right of the decimal separator is OK
				If Me.Text.Length - (intPos + 1) >= Me.NumberDecimals Then
					SetError(enuErrors.ErrTooManyDecimals)
					Return False
				End If
			Else
				'Check if the number of digits to the left of the decimal separator is OK
				If Me.Text.IndexOf("-") = -1 Then
					If intPos >= Me.NumberDigits Then
						SetError(enuErrors.ErrTooManyDigits)
						Return False
					End If
				Else
					If intPos - 1 > Me.NumberDigits Then
						SetError(enuErrors.ErrTooManyDigits)
						Return False
					End If
				End If
			End If
		End If

		'If we get through here, the value should be OK!!!
		Return True
	End Function

#End Region '-- Privates methods

#End Region     '-- Methods 

#Region " Subclassed events "

    Private Sub SCEnter(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Enter
        Try
            'Remove formatting characters
            MyBase.Text = Decimal.Parse(Me.Text, Globalization.NumberStyles.Any).ToString
        Catch
            'Nothing, just don't do it!!!
        End Try
        Me.SelectAll()
    End Sub

    Private Sub SCKeyPress(ByVal eventSender As System.Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles MyBase.KeyPress
		Dim KeyAscii As Integer = Convert.ToInt32(e.KeyChar)

        If KeyAscii = 8 Then
            '==============================================================================================
            '=== BackSpace
            '==============================================================================================
            'Let it do its job

        ElseIf KeyAscii = 3 Then
            '==============================================================================================
            '=== CTRL-C
            '==============================================================================================
            'Let it pass, validation will be done into the TextChanged event

        ElseIf KeyAscii = 22 Then
            '==============================================================================================
            '=== CTRL-V
            '==============================================================================================
            'Let it pass, validation will be done into the WndProc method

        ElseIf KeyAscii = 26 Then
            '==============================================================================================
            '=== CTRL-Z
            '==============================================================================================
            'Let it pass

        ElseIf e.KeyChar = System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator Then
            '==============================================================================================
            '=== Validation for .
            '==============================================================================================
            'E.Moreau 2003.11.02 - remove the selected text from the validation
            Dim strText As String
            If Me.SelectionLength > 0 Then
                strtext = Me.Text.Replace(Me.SelectedText, "")
            Else
                strtext = Me.Text
            End If

            ' if we already have a period, throw it away
            If strText.IndexOf(".") >= 0 Then
                SetError(enuErrors.ErrTooManyDot)
                KeyAscii = 0
            End If

            ' if we don't have decimals, throw it away
            If Me.NumberDecimals = 0 Then
                SetError(enuErrors.ErrDotNotAllowed)
                KeyAscii = 0
            End If

        ElseIf e.KeyChar = "-" Then
            '==============================================================================================
            '=== Validation for -
            '==============================================================================================

            'E.Moreau 2003.11.02 - remove the selected text from the validation
            Dim strText As String
            If Me.SelectionLength > 0 Then
                strtext = Me.Text.Replace(Me.SelectedText, "")
            Else
                strtext = Me.Text
            End If

            ' The number can only have one minus sign, so 
            ' if we already have one, throw this one away
            If strText.IndexOf("-") >= 0 Then
                SetError(enuErrors.ErrTooManyMinusSign)
                KeyAscii = 0
            End If

            ' if the insertion point is not sitting at zero
            ' (which is the beginning of the field), 
            ' throw away the minus sign (because it's not
            ' valid except in first position)
            If Me.SelectionStart <> 0 Then
                SetError(enuErrors.ErrMinusSignMisplaced)
                KeyAscii = 0
            End If

            ' do we allow negative numbers?
            If Me.ValueMin >= 0 Then
                SetError(enuErrors.ErrNegativeNotAllowed)
                KeyAscii = 0
            End If

        ElseIf e.KeyChar >= "0" And e.KeyChar <= "9" Then
            '==============================================================================================
            '=== Validation for numbers
            '==============================================================================================
			If Not ValidateKey() Then
				'SetError(enuErrors.ErrInvalidChar)
				KeyAscii = 0
			End If

        Else
            SetError(enuErrors.ErrInvalidChar)
            KeyAscii = 0
        End If

        If KeyAscii = 0 Then
            e.Handled = True
        End If
    End Sub

    Private Sub SCLeave(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Leave
        Try
            Me.Text = CType(Me.Text, Decimal).ToString(Me.DisplayFormat, Nothing)
        Catch
            SetError(enuErrors.ErrCannotApplyFormat)
        Finally
            If Me.Text.Length = 0 Then
				Me.Text = mdecDefaultValue.ToString(Me.DisplayFormat, Nothing)
            End If
        End Try
    End Sub

#End Region '-- Subclassed events 

#Region " Exposed Properties "

#Region " Overrides "
    Public Overrides Property Text() As String
        Get
            Return MyBase.Text
        End Get
        Set(ByVal Value As String)
			If Value Is Nothing Then Value = mdecDefaultValue.ToString
			If Me.ValidateFieldContent(Decimal.Parse(Value, Globalization.NumberStyles.Any).ToString) Then
				'MyBase.Text = Value
				'E.Moreau 2003/10/26
				'Formater quand une valeur est donnée à la propriété TEXT
				MyBase.Text = CType(Value, Decimal).ToString(Me.DisplayFormat, Nothing)
			Else
				SetError(enuErrors.ErrInvalidValue, Value)
			End If
        End Set
    End Property
#End Region '-- Overrides

#Region " Custom "

    'This property contains the display format
	<CategoryAttribute("S2iNumericTextBox Properties"), _
		DescriptionAttribute("The default value (also the value when the control is left empty).")> _
		Public Property DefaultValue() As Decimal
		Get
			Return mdecDefaultValue
		End Get
		Set(ByVal Value As Decimal)
			mdecDefaultValue = Value
		End Set
	End Property

	'This property contains the display format
	<CategoryAttribute("S2iNumericTextBox Properties"), _
		DescriptionAttribute("The display format (passed to Decimal.ToString)")> _
		Public Property DisplayFormat() As String
		Get
			Return mstrDisplayFormat
		End Get
		Set(ByVal Value As String)
			mstrDisplayFormat = Value
		End Set
	End Property

	'This property dictates the language of error messages
	<CategoryAttribute("S2iNumericTextBox Properties"), _
		DescriptionAttribute("The language of error messages")> _
		Public Property ErrorMessageLanguage() As enuLangueMessage
		Get
			Return mintErrorLanguage
		End Get
		Set(ByVal Value As enuLangueMessage)
			mintErrorLanguage = Value
		End Set
	End Property

	'This property contains the number of digits (to the right of the decimal point)
	<CategoryAttribute("S2iNumericTextBox Properties"), _
		DescriptionAttribute("The number of digits (to the right of the decimal point)")> _
		Public Property NumberDecimals() As Byte
		Get
			Return mbytNumberDecimals
		End Get
		Set(ByVal Value As Byte)
			mbytNumberDecimals = Value
		End Set
	End Property

	'This property contains the maximum number of digits (decimals included)
	<CategoryAttribute("S2iNumericTextBox Properties"), _
		DescriptionAttribute("The maximum number of digits (decimals excluded)")> _
	Public Property NumberDigits() As Byte
		Get
			Return mbytNumberDigits
		End Get
		Set(ByVal Value As Byte)
			mbytNumberDigits = Value
		End Set
	End Property

	<CategoryAttribute("S2iNumericTextBox Properties"), _
	 DescriptionAttribute("The maximum value the textbox can contain")> _
	 Public Property ValueMax() As Decimal
		Get
			Return mdecValueMax
		End Get
		Set(ByVal Value As Decimal)
			mdecValueMax = Value
		End Set
	End Property

	<CategoryAttribute("S2iNumericTextBox Properties"), _
	 DescriptionAttribute("The minimum value the textbox can contain")> _
	 Public Property ValueMin() As Decimal
		Get
			Return mdecValueMin
		End Get
		Set(ByVal Value As Decimal)
			mdecValueMin = Value
		End Set
	End Property
#End Region '-- Custom

#Region " Error Provider "

    <CategoryAttribute("S2iNumericTextBox Properties"), _
        DescriptionAttribute("BlinkRate property of the Provider control.")> _
    Public Property ErrProviderBlinkRate() As Integer
        Get
            Return ErrorProvider1.BlinkRate
        End Get
        Set(ByVal Value As Integer)
            ErrorProvider1.BlinkRate = Value
        End Set
    End Property

    <CategoryAttribute("S2iNumericTextBox Properties"), _
        DescriptionAttribute("BlinkStyle property of the Provider control.")> _
    Public Property ErrProviderBlinkStyle() As ErrorBlinkStyle
        Get
            Return ErrorProvider1.BlinkStyle
        End Get
        Set(ByVal Value As ErrorBlinkStyle)
            ErrorProvider1.BlinkStyle = Value
        End Set
    End Property

    <CategoryAttribute("S2iNumericTextBox Properties"), _
        DescriptionAttribute("Icon property of the Provider control.")> _
    Public Property ErrProviderIcon() As Icon
        Get
            Return ErrorProvider1.Icon
        End Get
        Set(ByVal Value As Icon)
            ErrorProvider1.Icon = Value
        End Set
    End Property

    <CategoryAttribute("S2iNumericTextBox Properties"), _
        DescriptionAttribute("IconAlignment property of the Provider control.")> _
    Public Property ErrProviderIconAlignment() As ErrorIconAlignment
        Get
            Return ErrorProvider1.GetIconAlignment(Me)
        End Get
        Set(ByVal Value As ErrorIconAlignment)
            ErrorProvider1.SetIconAlignment(Me, Value)
        End Set
    End Property

    <CategoryAttribute("S2iNumericTextBox Properties"), _
        DescriptionAttribute("Will the Error Provider control be visible?")> _
    Public Property ErrProviderVisible() As Boolean
        Get
            Return mblnErrorProviderVisible
        End Get
        Set(ByVal Value As Boolean)
            mblnErrorProviderVisible = Value
        End Set
    End Property
#End Region '-- Error Provider 

#End Region '-- Exposed Properties

End Class


' NumericTBEventArgs: a custom event inherited from EventArgs.
Public Class NumericTBEventArgs
    Inherits EventArgs

    Public Sub New(ByVal pMessage As String, ByVal pValue As String)
        Me.Message = pMessage
        Me.Value = pValue
    End Sub

    Public Message As String
    Public Value As String
End Class
'end of class NumericTBEventArgs
>Does Ctrl+V count as one keypress or two keypresses?
>Considder the following code that I have in my OnKeyPress
>
>protected override void OnKeyPress(System.Windows.Forms.KeyPressEventArgs e)
>{
>	switch(e.KeyChar)
>	{
>		case '\b':
>		case '0':
>		case '1':
>		case '2':
>		case '3':
>		case '4':
>		case '5':
>		case '6':
>		case '7':
>		case '8':
>		case '9':
>		{
>			e.Handled = false;
>		}break;
>//		case System.Windows.Forms.Keys.ControlKey + System.Windows.Forms.Keys.V:
>//		{
>//			System.Windows.Forms.MessageBox.Show("ctrl+v");
>//                         e.Handled = false;
>//		}break;
>		default:
>		{
>			e.Handled = true;
>		}break;
>	}
>}
>
>I have commented out some of the code above, because it doesn't compile. Any hints regarding how I can allow paste would be appreciated.
>
>Thanks,
>Einar
Éric Moreau, MCPD, Visual Developer - Visual Basic MVP
Conseiller Principal / Senior Consultant
Moer inc.
http://www.emoreau.com
Previous
Reply
Map
View

Click here to load this message in the networking platform