My biggest problem here is to get the CTRL-V (Paste) to work. I've tested many ctrl-v ascii code but I got none of them to work. CtrlX and CtrlC works perfetly so I don't know what the problem is. This is my half working code:
Private Sub alltb_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txtF.KeyPress, txtCLL.KeyPress, txtCLU.KeyPress
e.Handled = Not (Char.IsDigit(e.KeyChar) Or e.KeyChar = "." Or e.KeyChar = " " Or Asc(e.KeyChar) = 8 Or Asc(e.KeyChar) = 235 Or Asc(e.KeyChar) = 1 Or Asc(e.KeyChar) = 3 Or Asc(e.KeyChar) = 26 Or Asc(e.KeyChar) = 22 Or Asc(e.KeyChar) = 24)
End Sub
If you could suggest new code that will only allow numbers, decimals, space, backspace/delete, and shortcuts Or help me be able to use ctrlV, that would be really amazing and a big help!
CodePudding user response:
Things are actually a bit more complex even than the first answer suggests because the user might select paste a valid number within another valid number to create an invalid input, so you need to validate the result of the paste, not just the text being pasted.
You also need to consider that the user might enter one or more characters that are valid but then leave a result that is not. Here's a basic implementation I wrote some years ago:
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
In case you're interested, here is a more rigorous implementation, although I'm not 100% sure that there aren't still some bugs in this one as I haven't looked at it for a long time.
CodePudding user response:
When you press Ctrl V
keys in an edit-box like the TextBox
control, you actually request a string containing the text data on the system Clipboard
if any. So, the TextBox.KeyPress
event is not the right place to validate the pastes. You need a way to trap the WM_PASTE
messages and validate the string that returns from the Clipboard.GetText()
method.
For that and the keyboard inputs, create a new class and inherit from the TextBox
control, override the OnKeyPress
and WndProc
methods to apply your input condition(s).
Public Class TextBoxEx
Inherits TextBox
Const WM_PASTE As Integer = &H302
Protected Overrides Sub OnKeyPress(e As KeyPressEventArgs)
If Not Char.IsControl(e.KeyChar) AndAlso Not Char.IsWhiteSpace(e.KeyChar) Then
Dim s = Text.Insert(SelectionStart, e.KeyChar)
If Not Decimal.TryParse(s.Replace(" ", ""), Nothing) Then
e.Handled = True
End If
End If
MyBase.OnKeyPress(e)
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)
If m.Msg = WM_PASTE AndAlso Clipboard.ContainsText() Then
Dim s = Text.Remove(SelectionStart, SelectionLength).
Insert(SelectionStart, Clipboard.GetText().Replace(" ", ""))
If Not Decimal.TryParse(s, Nothing) Then Return
End If
MyBase.WndProc(m)
End Sub
End Class