Handling KeyCode/KeyChar events in Windows Form TextBox Control - vb.net

I have various input textboxes on my form. And based on entries made in each of the input textboxes, I update the display textbox. However, using AppendText message of textbox. I have my input textboxes set to accept only numeric values. So for each character inputted correctly, I update the display Textbox. Problem I have is when user selects Key.Back or Key.Delete, what I would like to do is do a Delete of last character in the display textbox, but I am yet to get this right. How do I delete the last character in the string that is contained in a TextBox using AppendText() or any of the utility functions available in that control please?
If (e.KeyChar = ChrW(Keys.Back)) Then
txtDisplay.Text -= 1
txtDisplay.Update()
ElseIf (Not (Char.IsDigit(e.KeyChar) Or Char.IsControl(e.KeyChar) Or (e.KeyChar = "."))) Then
e.Handled = True
Else
txtDisplay.AppendText(e.KeyChar)
End If

Use this in KeypPress event handler of txtDisplay
If e.KeyChar = ChrW(Keys.Back) Then
If txtDisplay.Text.Length > 0 Then
txtDisplay.Text = txtDisplay.Text.Substring(0, txtDisplay.TextLength - 1)
txtDisplay.SelectionStart = txtDisplay.Text.Length
End If
ElseIf (Not (Char.IsDigit(e.KeyChar) Or Char.IsControl(e.KeyChar) Or (e.KeyChar = "."))) Then
e.Handled = True
End If

Related

Best way to handle invalid input data in WinForms?

I've put together a form in which a user can dynamically generate a customer order with one or more order positions. For each position, there are several attributes like amount, product name, price, discount etc.
My main problem is: What is the best way to deal with invalid values for the input fields? For example if a user types "X" into the amount field instead of 1, 2 or whatever.
The basic idea was to let the user enter everything they want - but the order can only be saved once every input field contains valid data. If not, all invalid fields will be highlighted so the user knows what he did wrong.
So far, this seems to work just fine but my idea was to also have a Customer_Order object which would be updated everytime the user changes the value of an input field.
Obviously I could not do that if I want to allow the user to enter Strings like "X" into Integer or Decimal fields... so it seems to me that I have 2 options:
A: Either restrict the input fields and programatically turn invalid values into zeros (For example: User enters "abc" into price field -> String will be converted to 0,00)
OR B: keep my original plan with not so strict input regulations and NOT have a Customer_Order object that is always kept up to date. I would instead create the object from scratch and fill it with all the data from the input fields when the user finishes the order.
My problem with A is that I would like to keep the input fields as non-strict as possible. If a user types in something invalid, they should SEE what they typed in instead of the program changing the value. And my problem with B is that having an always up-to-date object of the customer order makes it easier to calulate prices on the fly. If I don't have that object, I would have to read out and parse all the necessary input fields every time I want to calculate something.
I'm not that experienced with GUIs so I really don't know if I'm missing something here... what would be the most elegant way to handle this? Is it generally a bad idea to have an always up-to-date object in the background at all times?
One option is to only allow valid keys. This can be done by utilizing the KeyDown event handler.
Create a new Windows Forms App (.NET Framework) project
Add a TextBox to the form (name: textBoxAmount)
Open Solution Explorer
In VS menu, click View
Select Solution Explorer
Open Properties Window
In VS menu, click View
Select Properties Window
Add TextBox KeyDown event handler
In Properties Window, select textBoxAmount from the drop-down
Click
Double-click KeyDown
Add module (name: HelperInput.vb)
Click Project
Select Add Module... (name: HelperInput.vb)
Click OK
HelperInput.vb:
Imports System.Globalization
Module HelperInput
Public Sub TBKeyDownMonetaryValue(sender As Object, e As System.Windows.Forms.KeyEventArgs)
Dim tb As Control = DirectCast(sender, Control) 'TextBox
Dim isKeyAllowed As Boolean = False
Dim nfInfo As NumberFormatInfo = CultureInfo.CurrentUICulture.NumberFormat
Debug.WriteLine($"currency symbol: {nfInfo.CurrencySymbol} decimal separator: {nfInfo.CurrencyDecimalSeparator} number group separator: {nfInfo.NumberGroupSeparator} currency group separator: {nfInfo.CurrencyGroupSeparator}")
If Not Control.ModifierKeys = Keys.Shift Then
Select Case e.KeyCode
Case Keys.Enter
isKeyAllowed = True
Case Keys.Back
isKeyAllowed = True
Case Keys.Delete
isKeyAllowed = True
Case Keys.NumPad0
isKeyAllowed = True
Case Keys.NumPad1
isKeyAllowed = True
Case Keys.NumPad2
isKeyAllowed = True
Case Keys.NumPad3
isKeyAllowed = True
Case Keys.NumPad4
isKeyAllowed = True
Case Keys.NumPad5
isKeyAllowed = True
Case Keys.NumPad6
isKeyAllowed = True
Case Keys.NumPad7
isKeyAllowed = True
Case Keys.NumPad8
isKeyAllowed = True
Case Keys.NumPad9
isKeyAllowed = True
Case Keys.D0
isKeyAllowed = True
Case Keys.D1
isKeyAllowed = True
Case Keys.D2
isKeyAllowed = True
Case Keys.D3
isKeyAllowed = True
Case Keys.D4
isKeyAllowed = True
Case Keys.D5
isKeyAllowed = True
Case Keys.D6
isKeyAllowed = True
Case Keys.D7
isKeyAllowed = True
Case Keys.D8
isKeyAllowed = True
Case Keys.D9
isKeyAllowed = True
Case Else
isKeyAllowed = False
End Select
End If
'only allow one currency decimal separator
If e.KeyCode = Keys.Oemcomma AndAlso nfInfo.CurrencyDecimalSeparator = "," AndAlso (String.IsNullOrEmpty(tb.Text) OrElse Not tb.Text.Contains(nfInfo.CurrencyDecimalSeparator)) Then
isKeyAllowed = True
ElseIf e.KeyCode = Keys.OemPeriod AndAlso nfInfo.CurrencyDecimalSeparator = "." AndAlso (String.IsNullOrEmpty(tb.Text) OrElse Not tb.Text.Contains(nfInfo.CurrencyDecimalSeparator)) Then
isKeyAllowed = True
End If
If Not isKeyAllowed Then
e.Handled = True
e.SuppressKeyPress = True
End If
End Sub
End Module
Form1.vb:
Public Class Form1
Private Sub TextBoxAmount_KeyDown(sender As Object, e As KeyEventArgs) Handles TextBoxAmount.KeyDown
HelperInput.TBKeyDownMonetaryValue(sender, e)
End Sub
End Class
Resources:
NumberFormatInfo Class

Make richtextbox single line only

Is it possible to make a richtextbox only able to contain one line? I want it to have the wraptext ability but I can't have multiple lines in the file it will generate.
You can set its AcceptsReturn attribute to false that should only allow one line because it won't let the text return.
If for some reason your properties window doesn't have the AcceptsReturn property, you can add if e.KeyCode = Keys.Enter Then e.SuppressKeyPress = True under the event KeyDown (as suggested by Jimi).
Simply think first,how do we get to the next line ? By pressing Return or Enter.So,in the KeyPress event of the RichTextbox you can simply use :
If e.KeyChar = Keys.Return Then
e.Handled = True
End if
Now this has a major drawback and that is : What if a user copy pastes a multi-line text into the richtextbox ?
To fix that, you can simply apply the following code in the TextChanged event :
Private Sub Rtb_TextChanged()
Dim lcount as Integer = rtb.Lines.Count
Dim i As Integer
If lcount > 1 Then
For i = 2 to lcount - 1
Dim index As Integer = rtb.GetFirstCharIndexFromLine(i)
Dim count As Integer = rtb.GetFirstCharIndexFromLine(i + 1) - start_index
rtb.Text = rtb.Text.Remove(index, count)
Next
End if
End Sub
Hope this helps :)

textbox without decimal causing issue with > sign

I have a text box in which i don't want decimal, so I am restricting user to key in decimal by checking in keydown event.
However, this is causing issue with ">" sign as user is not able to enter ">" sign in text box.
If Not e.Handled AndAlso e.Key = Key.Decimal OrElse e.PlatformKeyCode = 190 OrElse e.PlatformKeyCode = 110 Then
If e.Key <> Key.Back Then
e.Handled = True
End If
End If
Any inputs how can i solve?

vb word counter richtextbox covering multiple lines

I am programming novel management software, and I need to be able to keep track of the amount of words in the richtextbox accurately. This is what I have so far
Dim Change As Integer
Dim Count As Integer
Private Sub RichTextBox1_TextChanged(sender As Object, e As EventArgs) Handles RichTextBox1.TextChanged
Change = RichTextBox1.Text.Split(" ").ToLookup(Function(x) x).Count()
'Add 1 to the variable Change every time the space bar is pressed
Count = Change
If RichTextBox1.Text = "" Then
Count = 0
'If the textbox is empty, the word count is 0
ElseIf RichTextBox1.Text.EndsWith(" ") = True Then
Count = Change - 1
'take one away from the wordcount variable when the last character is a space
End If
ToolStripStatusLabel2.Text = Count
'Display the wordcount
End Sub
How do I get the code to keep going on multiple lines? So far, the code only runs on the text on the first line. If the user hits enter then keeps typing, the the word count doesnt count the first word on each subsequent lines
You can use something like this in the keydown handler. There may be some special cases for leading and trailing spaces, unless it can be off by 1, and backspaces should be handled.
If e.KeyValue = Keys.Space Or e.KeyValue = Keys.Back Then
ss = rText1.Text.Split
txCount.Text = UBound(ss) + 1
End If

How to represent backspace in a string?

Below is the code I am using to restrict user from entering any other characters except for the predefined ones. But using my code I cannot hit backspace.
How to include backspace also ?
Dim s As String = "0123456789$"
If s.IndexOf(e.KeyChar) = -1 Then
e.Handled = True
End If
a fine list of the Keys Enumeration
Keys.Back
like:
If e.KeyCode <> Keys.Back Then
.......
End If
ControlChars.Back should give you the backspace character.
as per previous posts:
Dim s As String = "0123456789$" & ControlChars.Back
If s.IndexOf(e.KeyChar) = -1 Then
e.Handled = True
End If