1

My problem:

I'm limiting a text box to 8 characters and showing a tooltip when it's exceeded (>8) rather than reached (=8). Using the .Maxlength function prevents the user from ever exceeding 8 characters so my >8 function is never fulfilled.

If I forgo the .Maxlength function and instead use .Substring to limit the input, my >8 function is fulfilled however the behavior differs from .Substring (the last rather than first 8 inputs are kept and I lose the alert sound).

It would a lot cleaner to be able to check for whenever .Maxlength is exceeded without affecting the first 8 inputs.

To reproduce:

  1. In Visual Studio, in design mode, drag a text box and tooltip onto a fresh form.
  2. Use the following as is:

Code:

Public Class Form1
    Private Sub Textbox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged
        TextBox1.MaxLength = 8
        If (Not IsNumeric(TextBox1.Text) And TextBox1.Text.Length > 0) Then
            If ToolTip1.GetToolTip(TextBox1) = "" Then
                ToolTip1.ToolTipTitle = "Input must be numeric!"
                ToolTip1.Active = True
                ToolTip1.IsBalloon = True
                ToolTip1.ToolTipIcon = ToolTipIcon.Warning
                ToolTip1.Show(vbNewLine, TextBox1, 45, -40)
            End If
        ElseIf TextBox1.Text.Length > 8 Then
            'TextBox1.Text = TextBox1.Text.Substring(0, 8)
            ToolTip1.IsBalloon = True
            ToolTip1.ToolTipTitle = "8 character maximum!"
            ToolTip1.Active = True
            ToolTip1.ToolTipIcon = ToolTipIcon.Warning
            ToolTip1.Show(vbNewLine, TextBox1, 45, -40)
        Else
            ToolTip1.Active = False
            ToolTip1.Hide(TextBox1)
        End If
    End Sub
End Class
Clarus Dignus
  • 3,847
  • 3
  • 31
  • 57
  • MaxLength should be a design-time property, so you don't have to worry about the user exceeding the maximum, since they won't be able to. – Joe Enos Oct 23 '14 at 17:59
  • 1
    using `ErrorProvider` might save a bit of code rather than creating all sorts of tool tips – Ňɏssa Pøngjǣrdenlarp Oct 23 '14 at 18:04
  • @JoeEnos The user will never be able to exceed the maximum but I've been asked to show a balloon tip if the user *attempts* to exceed the maximum. This is on the basis that the user may not know why they're being restricted. Regarding your design-time advice, is there a downside to setting `.MaxLength` in code? – Clarus Dignus Oct 23 '14 at 18:07
  • Your logic has a flaw. Consider the case when the user enters non numeric characters. The *TextBox1.Text.Length > 8* comparison is never executed. – γηράσκω δ' αεί πολλά διδασκόμε Oct 23 '14 at 18:14
  • You've probably got the cleanest solution for what you're looking for with LarsTech's answer - there are other ways, maybe handling `KeyPress` or `KeyDown`, but I think this one's going to be much simpler. About MaxLength, the property is persistent, so setting it in your event handler every time was redundant - once you set it, it's now the same as if you would have done it as design time - which is apparently not what you want to do in order to get your expected behavior. – Joe Enos Oct 23 '14 at 18:25
  • @γηράσκωδ'αείπολλάδιδασκόμε I've just tested it on my end and you're correct. I'm currently correcting the logic and will report back with the corrected code. – Clarus Dignus Oct 23 '14 at 18:25
  • @JoeEnos Thanks for the clarification and explaining the redundancy of not using the design time property and yes, as per LarsTech solution, I'm now using `.Substring` instead of `.Maxlength`. – Clarus Dignus Oct 23 '14 at 18:29
  • @Plutonix The Error Provider looks promising and would save a considerable amount of coding across my overall application. I wasn't aware it. I'll research it shortly. – Clarus Dignus Oct 23 '14 at 18:33
  • @γηράσκωδ'αείπολλάδιδασκόμε Logic corrected. Simplified example using message boxes: http://pastebin.com/YG2kxCDD | Full example using tooltips: http://pastebin.com/vJU74D7k – Clarus Dignus Oct 23 '14 at 23:40
  • It still has a problem when you enter non numeric characters and exceed 8 characters. The balloon inverts. – γηράσκω δ' αεί πολλά διδασκόμε Oct 24 '14 at 02:18
  • @γηράσκωδ'αείπολλάδιδασκόμε After further review, the only solution known to me is [a workaround you provided in a similarly coded example](http://stackoverflow.com/a/26528877/2971649). In reference to [the code of my penultimate comment](http://pastebin.com/vJU74D7k), I have an `If Not IsNumeric` condition parenting both >8 and >0 conditions. Currently, the >8 statement is parented in `If ToolTip1.GetToolTip()` which produces inversion...(continued)... – Clarus Dignus Oct 25 '14 at 11:31
  • @γηράσκωδ'αείπολλάδιδασκόμε ...(continued)... [Parenting >8 statement instead of >0 statement](http://pastebin.com/1rgL0YUF), [parenting >8 statement and >0 statement](http://pastebin.com/1vJnesVn) and [parenting `If Not IsNumeric` statement](http://pastebin.com/Y48vb0X6) each with `If ToolTip1.GetToolTip()` all prevent the triggering of >8. [Removing >0](http://pastebin.com/yx7vQYxf) prevents the inversion but at the expense of >0. These are the only permutations I can conceive with the knowledge I currently have. – Clarus Dignus Oct 25 '14 at 11:32
  • Instead of constantly checking `TextBox1.Text.Length > 8` you could put it in the begining and then check `Not IsNumeric(TextBox1.Text)`. You don't need `TextBox1.Text.Length > 0`. One more thing. Because you write the same code (showing the tooltip) all the time, put it in a fuction. I will give you an example I wrote as an answer. – γηράσκω δ' αεί πολλά διδασκόμε Oct 25 '14 at 16:04

3 Answers3

1

When you replace the text, it resets the caret, so move it back into place at the end:

TextBox1.Text = TextBox1.Text.Substring(0, 8)
TextBox1.Select(TextBox1.TextLength, 0)
LarsTech
  • 80,625
  • 14
  • 153
  • 225
  • Thanks, LarsTech (+1). That's a perfect solution for getting `.Substring` to behave more like `.Maxlength` but with regards to my overall problem, I still require a workaround for fulfilling the >8 condition for the tooltip to show. – Clarus Dignus Oct 23 '14 at 18:13
  • @ClarusDignus It shows in my form. Make sure to comment out the MaxLength line. – LarsTech Oct 23 '14 at 18:14
  • Apologies. I had the incorrect line commented out. Thanks again. – Clarus Dignus Oct 23 '14 at 18:19
1

It is better to supress the key if it is invalid:

Private Sub TextBox1_KeyPress(sender As System.Object, e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress
    Dim str As String

    str = TextBox1.Text
    str = str.Insert(TextBox1.SelectionStart, CStr(e.KeyChar))

    If e.KeyChar = ChrW(Keys.Back) Then
        HideToolTip()
    ElseIf str.Length > 8 Then
        ShowToolTip("8 character maximum!")

        e.Handled = True
    ElseIf Not IsNumeric(str) Then
        ShowToolTip("Input must be numeric!")

        e.Handled = True
    Else
        HideToolTip()
    End If

End Sub

Private Sub HideToolTip()
    If ToolTip1.GetToolTip(TextBox1) <> "" Then
        ToolTip1.Active = False
        ToolTip1.Hide(TextBox1)
    End If
End Sub

Private Sub ShowToolTip(ByVal str As String)
    'always check if tooltip is visible, to avoid inversion
    If ToolTip1.GetToolTip(TextBox1) = "" Then
        ToolTip1.ToolTipTitle = str
        ToolTip1.Active = True
        ToolTip1.IsBalloon = True
        ToolTip1.ToolTipIcon = ToolTipIcon.Warning
        ToolTip1.Show(vbNewLine, TextBox1, 45, -40, 1000)
    End If
End Sub

EDIT

There is a minor "bug" in IsNumeric() function as it allows numeric with spaces and multiple "."

8..888 'is numeric
.9999  'is numeric

To solve everything:

Private Sub TextBox1_KeyPress(sender As System.Object, e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress
    Dim str As String = "0123456789."

    If e.KeyChar = ChrW(Keys.Back) Then
        HideToolTip()
    ElseIf TextBox1.Text.Length = 8 Then
        ShowToolTip("8 character maximum!")

        e.Handled = True
    ElseIf e.KeyChar = "." And (TextBox1.Text.Contains(".") Or TextBox1.SelectionStart = 0) Then 'supress a second "." or a first one
        ShowToolTip("Input must be numeric!")

        e.Handled = True
    ElseIf Not str.Contains(CStr(e.KeyChar)) Then
        ShowToolTip("Input must be numeric!")

        e.Handled = True
    Else
        HideToolTip()
    End If

End Sub
0

Add this after the substring call

TextBox1.SelectionStart = 8
UnhandledExcepSean
  • 12,504
  • 2
  • 35
  • 51