Can I implement an autofill feature with a textbox?

C

Corbin

I'm trying to improve data-entry efficiency for users of my program.

One idea we had was to make certain textboxes work like the To: box in
an Outlook email message, where it autofills a suggested recipient
from your address box in response to the first letter or two that you
type.

So far, I have met with limited success in doing this. My approach
has been to try to make a textbox respond to the textchanged event by
checking the typed text against a form-level array of strings called
mAutoFill(). If it finds a match, it puts the remaining text in the
box, and selects the text that has been filled while leaving the typed
text unselected. The code I've come up with to do this is ugly, long,
and does not work perfectly.

(For example, after it autofills, if you hit backspace, it should
remove the selected text and leave the rest--this happens, but then it
analyzes the remaining text and autofills the same suggestion, making
it seem to the user that nothing happens when he hits backspace.)

That's just one example. Before making my code even more complicated
in an effort to fix that problem, (not to mention whatever other
problems are there) I wondered if anybody out there might be able to
suggest a more elegant way to implement autofill. Am I even using the
right control?

Here is my ugly, somewhat embarrassing code.

Private Sub txtAssignee_TextChanged(ByVal sender As Object, ByVal
e As System.EventArgs) Handles txtAssignee.TextChanged

Dim i As Integer, iLen As Integer
Static bLockout As Boolean

Try

If bLockout = False Then
bLockout = True
iLen = Len(txtAssignee.Text)
For i = LBound(mAutoFill) To UBound(mAutoFill)
If
UCase(mAutoFill(i)).StartsWith(UCase(txtAssignee.Text)) And
Len(mAutoFill(i)) > iLen Then
txtAssignee.Text = mAutoFill(i)
txtAssignee.Select(iLen, Len(txtAssignee.Text)
- iLen)
Exit For
End If
Next
End If

Catch ex As Exception
'ex handlers to be written later.
Finally
bLockout = False
End Try

End Sub
 
G

Greg Dunn

Am I even using the right control?

A sorted ComboBox gets you pretty darn close to what you want with almost no
coding. If you set the DroppedDown property of the ComboBox to True in the
Enter event, then wherever your user lands in the ComboBox, the list is
dropped down automatically. Then typing any sequence of letters followed by
the DOWN ARROW selects the closest match in the list.

Greg Dunn
 
C

Corbin

Greg,

Thanks for the suggestion. I have tried it and again I am not getting
the behavior that is desired. My problem with the combobox is that
every other place where I use comboboxes, the DropDownStyle property
is set to DropDownList, forcing the user to select an item rather than
entering a value not on the list. To avoid confusion, I don't want to
have some comboboxes that do enforce this and others that do not. So
if I use a cbo, it has to at least look like a textbox. This can be
achieved with a DropDownStyle set to Simple, but then even with your
suggested code in the Enter event it does not attempt to auto-complete
text as it is typed in or even when the cbo loses focus.

Is it possible to implement some form of auto-completion with a cbo
that is set to DropDownStyle=Simple? So far, I'm not having any luck.

Thanks,
Corbin
 
C

Corbin

Problem solved. I went ahead and used a textbox. Actually, I created
a dirt simple user control which inherits from the standard Windows
Forms textbox. It has one extended property, called AutofillArray, of
type ArrayList. If this property is set then the textbox uses it to
provide auto-completion functionality. If it's not set then the
control behaves exactly like a normal textbox.

Email me if you'd like me to send you the code.
 
G

Guest

As it turns out Greg Dunn's example using a combobox does NOT require you to
set the DroppedDown on entry and it DOES work with a Simple style combo. I
simply placed a single line high (textbox sized) combo on the form, set the
style to simple, filled the list with some test data (in the IDE) and then
ran the project.

I type some characters and hit the down arrow and get the closest match. If
the Sorted property is set to true then it work better when the first "hit"
isn't the correct one.

I'd like to see your example though...

Best, Steve
 
C

corbinamman

Thanks to Warmrain for the help. I don't want the user to have to hit
the arrow keys, though. In my component, each time a character is
typed, the Text property is evaluated against an array of possible
values, and if one is found then the rest of the suggested text is
appended to the already-typed text and the appended part is highlighted
so that if the user hits yet another key the appended suggestion will
be overwritten and the process starts over. Here's my user control. I
left out the code that was automatically generated by VS.NET. There is
nothing in there special. I would like to make this work so that if
there are multiple matches, you can cycle through them with the arrow
keys. But I didn't have time to work on this feature. If anyone wants
to post an edited version of this class that would do that, I would
appreciate it.

Public Class AutofillTextbox

Inherits System.Windows.Forms.TextBox

Private mAutoFill As New ArrayList
Private mblnLockout As Boolean
Private mintLastKeystroke As Integer

Public Property AutoFillArray() As ArrayList
Get
AutoFillArray = mAutoFill
End Get
Set(ByVal Value As ArrayList)
mAutoFill = Value
'sort the items in order that the items are matched
alphabetically
If Not mAutoFill Is Nothing Then mAutoFill.Sort()
End Set
End Property

Private Sub AutofillTextbox_TextChanged(ByVal sender As Object,
ByVal e As System.EventArgs) Handles MyBase.TextChanged

Dim iLen As Integer = Len(Me.Text)

Try

If mblnLockout = False And iLen > 0 And mintLastKeystroke
= 30 And Not mAutoFill Is Nothing Then

'avoid callilng this method recursively by setting this
flag to true.
mblnLockout = True

'cycle through the ArrayList in search of an item that
matches the typed text.
Dim myEnumerator As System.Collections.IEnumerator =
mAutoFill.GetEnumerator()
While myEnumerator.MoveNext()
If
UCase(myEnumerator.Current).StartsWith(UCase(Me.Text)) And
Len(myEnumerator.Current) > iLen Then
'a match is found, and there is text in the
match that needs to be appended and highlighted.
Me.Text = myEnumerator.Current
Me.Select(iLen, Len(myEnumerator.Current) -
iLen)
Exit While
End If
End While

Else
'at least one of the following 4 conditions are true,
thus no action is called for.
'1. mblnLockout is true: skip code to avoid infinite
recursion.
'2. there is nothing in the textbox to match with
'3. the keystroke that fired this event was backspace
or some other non-character ascii code.
'4. the AutoFillArray property is not set: there is
nothing to match the typed text with.
End If

Catch ex As Exception
'ex handlers to be written later.
Finally
mblnLockout = False
End Try

End Sub

Private Sub AutofillTextbox_KeyPress(ByVal sender As Object, ByVal
e As System.Windows.Forms.KeyPressEventArgs) Handles MyBase.KeyPress
mintLastKeystroke = AscW(e.KeyChar)

End Sub

End Class
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top