Check to see if selection/text was changed in form - vb.net

I have a form with about 20 controls on it (ComboBox, TextBox, etc) that I have pre-loaded with data. This is being displayed to the user and gives them the capability to change any of the fields.
I do not know the best way of recognizing that changes have taken place. After some research, I found TextBox.TextChanged and setting the flag IsDirty = True or something along those lines.
I don't think this will be 100% bulletproof since the user might change the value and then go back and change it to how it was when initially loaded. I've been thinking about saving the current data to .Tag and then comparing it with the .Text that was entered when the user clicks "Cancel" to simply ask them if they'd like to save the changes.
This is my code:
Private Sub Form1_Load(ByVal sender as Object, byVal e as System.EventArgs)Handles MyBase.Load
For Each ctr as Control in me.Controls
if typeof ctr is TextBox then
ctr.tag=ctr.text
end if
Next
End Sub
This is the code for when the user clicks "Cancel":
Private Sub CmdCancel_Click (ByVal sender as Object, ByVal e As System.EventArgs) Handles CmdCancel.Click
For each ctr As Control in Me.Controls
If Typeof ctr is Textbox then
if ctr.tag.tostring <> ctr.text then
MsgBox ("Do you want to save the items", YesNo)
end if
End if
Next
End sub
Is this an effective way to do this? Can it be relied on? If anyone has any better idea, I'd love to hear it.

Have a look at this:
For Each txtBox In Me.Controls.OfType(Of TextBox)()
If txtBox.Modified Then
'Show message
End If
Next
EDIT
Have a look at this. This may be of interest to you if you wanted an alternative way to the .Tag property:
'Declare a dictionary to store your original values
Private _textboxDictionary As New Dictionary(Of TextBox, String)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'You would place this bit of code after you had set the values of the textboxes
For Each txtBox In Me.Controls.OfType(Of TextBox)()
_textboxDictionary.Add(txtBox, txtBox.Text)
Next
End Sub
Then use this to find out the original value and compare to the new value:
For Each txtBox In Me.Controls.OfType(Of TextBox)()
If txtBox.Modified Then
Dim oldValue = (From kp As KeyValuePair(Of TextBox, String) In _textboxDictionary
Where kp.Key Is txtBox
Select kp.Value).First()
If oldValue.ToString() <> txtBox.Text Then
'Show message
End If
End If
Next

I know this already has an accepted answer, but I thought the part about checking if the actual text value has changed should be addressed. Checking modified will reveal if any changes were made to the text, but it will fail if the user, for example, adds a character and then deletes it. I think a good way to do this would be with a custom control, so here's an example of a simple control that stores the textbox's original text whenever it is changed programmatically, and has a textaltered property that can be checked to show whether or not the user's modifications actually resulted in the text being different from its original state. This way, each time you fill the textbox with data yourself, the value you set is saved. Then when you are ready, you just check the TextAltered property:
Public Class myTextBox
Inherits System.Windows.Forms.TextBox
Private Property OriginalText As String
Public ReadOnly Property TextAltered As Boolean
Get
If OriginalText.Equals(MyBase.Text) Then
Return False
Else
Return True
End If
End Get
End Property
Public Overrides Property Text As String
Get
Return MyBase.Text
End Get
Set(value As String)
Me.OriginalText = value
MyBase.Text = value
End Set
End Property
End Class

Related

Is there any way to create a global function to clear TextBoxes?

I was wondering if there is any way to create a class with a global function/method/sub that upon
calling it will clear some of the textboxes of the form. How can i handle the different number of textboxes
each forms has?
The current code clears only the pre-defined 2 boxes. Thank you.
Public Class ClearElements
Public Sub CLEAR_TEXT(ByVal text1 As TextBox, ByVal text2 As TextBox)
text1.Clear()
text2.Clear()
End Sub
End Class
There are many ways to do it.
You can add the TextBoxes to a List, and clear each item in the list
Private ReadOnly someOfTheTextBoxes As New List(Of TextBox)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
someOfTheTextBoxes.Add(TextBox1)
someOfTheTextBoxes.Add(TextBox2)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For Each t In someOfTheTextBoxes
t.Clear()
Next
End Sub
Or make this method
Public Sub CLEAR_TEXT(textboxes As IEnumerable(Of TextBox))
For Each t In textboxes
t.Clear()
Next
End Sub
and call it with your list of TextBoxes
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
CLEAR_TEXT(someOfTheTextBoxes)
End Sub
or make an array on the spot and pass it in
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
CLEAR_TEXT({TextBox1, TextBox2})
End Sub
If you are interested in recursion at all, here are some extensions I have which could help
Module Extensions
<Runtime.CompilerServices.Extension>
Public Function ChildControls(parent As Control) As IEnumerable(Of Control)
Return ChildControls(Of Control)(parent)
End Function
<Runtime.CompilerServices.Extension>
Public Function ChildControls(Of TControl As Control)(parent As Control) As IEnumerable(Of TControl)
Dim result As New List(Of TControl)
For Each ctrl As Control In parent.Controls
If TypeOf ctrl Is TControl Then result.Add(CType(ctrl, TControl))
result.AddRange(ctrl.ChildControls(Of TControl)())
Next
Return result
End Function
<Runtime.CompilerServices.Extension>
Public Function ForEach(Of TSource)(source As IEnumerable(Of TSource), action As Action(Of TSource)) As IEnumerable(Of TSource)
For Each item As TSource In source
action(item)
Next item
Return source
End Function
<Runtime.CompilerServices.Extension>
Public Function ForEach(Of TSource)(source As IEnumerable(Of TSource), action As Action(Of TSource, Integer)) As IEnumerable(Of TSource)
For i As Integer = 0 To source.Count() - 1
action(source.ElementAt(i), i)
Next
Return source
End Function
End Module
Clear all textboxes recursively
Me.ChildControls(Of TextBox).ForEach(Sub(t) t.Clear())
Or ForEach on your list
someOfTheTextBoxes.ForEach(Sub(t) t.Clear())
We have this:
You could recursively go through all the controls in the form and in case of type = Textbox clear it.
But then the plot thickens:
I've done that before. It clears all the boxes of the form. I am talking about the case where some boxes have to be untouched and some to cleared.
The solution here is two parts. First, create the recursive method as suggested like this:
Public Sub ClearText(root As Control)
For Each ctrl As Control In Root.Controls
If TypeOf ctrl Is TextBox Then ctrl.Text = String.Empty
ClearText(ctrl)
Next ctrl
End Sub
or this:
Public Sub ClearText(root As IEnumerable(Of Control))
For Each ctrl As Control In root
If TypeOf ctrl Is TextBox Then ctrl.Text = String.Empty
ClearText(ctrl.Controls)
Next ctrl
End Sub
Second, on your form, use a container like Panel, GroupBox, FlowLayoutPanel, etc for the TextBox controls you need to clear. The key is all of the TextBox controls you need to clear — and none of the ones you want to keep — should be in same common container. Once that is done, you can pass the container to one of the above methods. If this messes with your layout, you can have a small number of containers for sets of controls on different areas of the form and call the function just a few times.
Remember, Panel controls can be styled to leave no visible artifacts on the parent form at all, and used entirely for logical groupings. The second version of the method above will also allow you to create arrays or lists of the controls (or control containers) you care about.
Another way to control this is to inherit a custom control from TextBox. You don't even need to change anything. All that matters is the control is now a different type from a regular textbox, and so the recursive method can target your new control type instead of textbox.
I'm using For in some cases.
First is to know for what do you need Textboxes or any component.
Second is to know if Textboxes (or any other component) will be inside Form (root) or inside others components like panels, groupoxes, tabPages… and if them will be inside of others.
Example1: Form – GroupBox(x) – TabControl(y) – TabPage(z) – TextBox(n)
Example2: Form --- TextBox(x)
Example3: Form – GroupBoox(x) – Panel(y) – TextBox(n)
Etcetera.
You may to create some anidated subs/functions to complete something more elaborated. There are two important things:
Path of the component (see previous examples)
Number of the component. If you follow Example3, maybe could be this:
Form1 – GroupBox2 – Panel1 – TextBox3
Important: These are names of the components, and you need must be enumerated all of them.
The easy way to do what you are asking is:
Public Sub CountTextBoxesAndClear(ByVal FormName As String, Optional ByVal myObject As Object = Nothing)
Dim ArrayTextBoxName() As String
Dim myTextBox As New TextBox
Dim nTBOX As Integer
'Path of component
If myObject = Nothing Then myObject = My.Application.OpenForms.Item(FormName)
'Bucle
For i As Integer = 0 To myObject.Controls.Count - 1
If myObject.Controls(i).GetType Is GetType(TextBox) Then
'Counting
nTBOX += 1
'Redim array
ReDim Preserve ArrayTextBoxName(nTBOX)
'Get Component
ArrayTextBoxName(nTBOX) = "TextBox" & nTBOX
'Get Path
myTextBox = myObject.Controls.Item(ArrayTextBoxName(nTBOX))
'myTextBox = myObject.Controls.Item("TextBox" & nTBOX) '<< the same of above line
Try
'Clear TextBoxes
myTextBox.Clear()
Catch ex As NullReferenceException
'A TextBox is Null, no error message
End Try
End If
Next
End Sub
FormName is the name of Form, with quotes, for example “Form1”.
myObject is the object that contains textboxes, if Textboxes are inside of a Panel named Panel1, you must write Panel1 (without quotes).
Try/Catch: Maybe you need to have Textbox1, TextBox2, Textbox4, Textbox5, AnotherTextBox1, AnotherTextBox2.
And you call your sub:
CountTextBoxesAndClear("Form1")
If TextBoxes are into a Panel named Panel1:
CountTextBoxesAndClear("Form1", Panel1)
You must to have the total of textboxes but only clear (or do any action) only for TextBoxes named TextBox[x].
Try/Catch manage the error because TextBox3 does not exist. However, the correct way is Textbox1, TextBox2, Textbox3, Textbox4, AnotherTextBox1, AnotherTextBox2 and put limits in your sub/function.
For example:
Public Sub CountTextBoxesAndClear(ByVal FormName As String, Optional ByVal myObject As Object = Nothing, Optional byval start as integer = 0, Optional byval finish as integer = 0)
[…tracatra…]
For i As Integer = start To finish
[…tratra…]
Next
End Sub
And this is how to call:
CountTextBoxesAndClear("Form1", Nothing, 1, 4)
And now, you can investigate a little bit about how create subs/functions to know correct paths of components, and get contents and properties of TextBoxes, Labels, Comboboxes, checkboxes…
Additional info:
If you are working in VisualStudio, you know that if you change a name of component, all of code is changed automatically. This is a big problem if you are using start/finish vars as numbers because, you must to change manually all start/finish values in functions when you need to add/remove or move positions, for example:
CountTextBoxesAndClear("Form1", Nothing, 8, 12)
Now you need to add a new TextBox just in the eight position and move one. Your sub looks like this:
CountTextBoxesAndClear("Form1", Nothing, 9, 13)
You can create a simply function that convert the name of the component to integer (this function is only for two digits (0 to 99):
Public Function ObjToInt(ByVal IntObject As Object) As Integer
If IntObject IsNot Nothing Then
Dim ref As Integer = Val(IntObject.Name.Substring(IntObject.Name.Length - 2))
If ref = 0 Then
ref = Val(IntObject.Name.Substring(IntObject.Name.Length - 1))
End If
Return ref
Else
Return 0
End If
End Function
And your sub may be written like this:
CountTextBoxesAndClear("Form1", Nothing, ObjToInt(TextBox9), ObjToInt(TextBox13))
Thanks for your awesome solutions.
I finally figured it out using ParamArray
Public Sub CLEAR_TEXTBOXES(ParamArray arr_textboxes() As TextBox)
For Each textbox As TextBox In arr_textboxes
textbox.Clear()
Next
End Sub
Then i call class using whatever textbox i want,
CLS_CLEAR_TEXTBOX.CLEAR_TEXTBOXES(TextBox1, TextBox2, Textbox7)
It's more shorter method.
Use ParamArray and Linq.
Public Sub CLEAR_TEXT(ParamArray text As TextBox())
text.ToList().ForEach(Sub(s) s.Clear())
End Sub

Hyperlinks inside ListBox

Hello, can someone help me with my project that I'm working on? Anything is appreciated!
So, what do I need? Its simple, I need link and name bars to actually create a hyperlink into the LSB listbox. Can someone please help me??
PS: Could you please keep it simple for me, I just started with this language.
OK This isn't as simple as I would like it to be for you but here goes. I'll try to explain as I go along
OK all the bits code below goes in your Form1 class as one lump - without my explanations that is. What I've done here is create a new class called Hyperlink
It has a couple of properties called Name and Link and a constructor called New
Class HyperLink
Private friendlyName As String
Private link As String
Public Property Name As String
Get
Return friendlyName
End Get
Set(ByVal value As String)
friendlyName = value
End Set
End Property
Public Property URL As String
Get
Return link
End Get
Set(value As String)
link = URL
End Set
End Property
Public Sub New(nm As String, ln As String)
friendlyName = nm
link = ln
End Sub
End Class
Here I'm creating list called linkList - this will hold the list of hyperlinks - I'm doing this so that later on the listbox will be set to use this as it's source of list items
Dim linklist As New List(Of HyperLink)
This sub called addLinkToListbox actually does several things. The important bits are that it tells you program to temporarily stop responding when the index of the listbox changes(which happens even when you're changing the contents off the listbox)
Then it adds a new **hyperlink* to the list of hyperlinks taking data from the link textbox and the name textbox.
To actually refresh the data shown in the textbox, I have to change the listbox datasource to nothing and then back to to the linkList
The next two lines tell the listbox to display the Name property inn the list box and when the item is actually clicked, to return the URL property.
Finally, I tell the program to start responding again when the index of the listbox index changes.
Private Sub addLinkToListbox(linkName As String, linkURL As String)
RemoveHandler ListBox1.SelectedIndexChanged, AddressOf ListBox1_SelectedIndexChanged
linklist.Add(New HyperLink(linkName, linkURL))
ListBox1.DataSource = Nothing
ListBox1.DataSource = linklist
ListBox1.DisplayMember = "Name"
ListBox1.ValueMember = "URL"
AddHandler ListBox1.SelectedIndexChanged, AddressOf ListBox1_SelectedIndexChanged
End Sub
These last two bits of code are hopefully self-explanatory
Private Sub btnAddLink_Click(sender As Object, e As EventArgs) Handles btnAddLink.Click
addLinkToListbox(txtName.Text, txtLink.Text)
End Sub
Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
MessageBox.Show(ListBox1.SelectedValue.ToString)
End Sub

Form Control Validation for User Input in (VB.NET 2005)

I am writing an application for my Notary business. I am a Notary Public in Iowa.
I have many types of control on the form. ComboBox (that can be modified), TextBox and MaskedTextBox.
I know I can use the TextBoxBase class to cover the TextBox and also the MaskedTextBox, but my validation code is not doing anything. Nothing happens.
I have an ErrorProvider on the form called ErrorProvider. It has the "AutoValidate" option set to "EnableAllowFocusChange". The BlinkStyle is set to AlwaysBlink. All other properties are default.
I have three buttons on the form, too. Reset, Save and Close. Both the Reset and Close buttons are set to CausesValidation = False and the Save button is set to CausesValidation = True.
I need to make sure the "required" fields have a value when the Save button is clicked.
So, I figured I would use the Validated and Validating events of the controls. But, when clicking Save, nothing happens. The ErrorProvider doesnt even show. If I leave the control empty, still nothing happens.
This is my code:
Private Sub Company_Validated(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles Company.Validated, CompanyAddress.Validated, CompanyCity.Validated, CompanyZipCode.Validated, CompanyPhone.Validated, CompanyAddressRemit.Validated, CompanyCityRemit.Validated, CompanyZipCodeRemit.Validated
ErrorProvider.SetError(CType(sender, TextBoxBase), String.Empty)
End Sub
Private Sub Company_Validating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) _
Handles Company.Validating, CompanyAddress.Validating, CompanyCity.Validating, CompanyZipCode.Validating, CompanyPhone.Validating, CompanyAddressRemit.Validating, CompanyCityRemit.Validating, CompanyZipCodeRemit.Validating
Dim ErrorMessage As String = String.Empty
Dim TheField As TextBoxBase = CType(sender, TextBoxBase)
If TypeOf TheField Is MaskedTextBox Then
CType(TheField, MaskedTextBox).TextMaskFormat = MaskFormat.ExcludePromptAndLiterals
End If
If Not IsValid(TheField, ErrorMessage) Then
e.Cancel = True
TheField.Select(0, TheField.Text.Length)
ErrorProvider.SetError(TheField, ErrorMessage)
End If
End Sub
Private Function IsValid(ByVal ControlName As TextBoxBase, ByVal ErrorMessage As String) As Boolean
If String.IsNullOrEmpty(ControlName.Text.ToString) Then
ErrorMessage = "This is a required field."
Return False
Else
ErrorMessage = String.Empty
Return True
End If
End Function
Any ideas on what I am doing wrong?
The String class in vb.net is a bit "odd". It's a reference type that acts (not all cases) like a value type. You need to change ByVal to ByRef.
Private Function IsValid(ByVal ControlName As TextBoxBase, ByRef ErrorMessage As String) As Boolean

How to create Control Arrays in VB .NET

In VB6 there is a feature called Control Arrays, where you name controls the same name and provide them an index value. This allows you to set a value by looping through the controls and setting each value. In VB .NET I can't create a control array could someone provide me with a similar solution.
Here is a sample I wrote for something else that shows how to do something similar and shows how to do the handler as well. This makes a 10x10 grid of buttons that turn red when you click them.
Dim IsCreated(99) As Boolean
Dim Buttons As New Dictionary(Of String, Button)
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
For i As Integer = 0 To 99
Dim B As New Button
Me.Controls.Add(B)
B.Height = 30
B.Width = 40
B.Left = (i Mod 10) * 41
B.Top = (i \ 10) * 31
B.Text = Chr((i \ 10) + Asc("A")) & i Mod 10 + 1
Buttons.Add(B.Text, B)
B.Tag = i
AddHandler B.Click, AddressOf Button_Click
Next
End Sub
Private Sub Button_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim B As Button = sender
IsCreated(B.Tag) = True
B.BackColor = Color.Red
End Sub
Avoid using the proposed iteration approaches, you'll get a fairly random collection of controls unless your form is very simple. Simply declare the control array in your code and initialize it in the form constructor. Like this:
Public Class Form1
Private OrderNumbers() As TextBox
Public Sub New()
InitializeComponent()
OrderNumbers = New TextBox() {TextBox1, TextBox2}
End Sub
End Class
You can now treat OrderNumbers just like you could in VB6.
Maybe this is simpler. To create a control array, I put the control array declaration in a module. For example, if I have a Form with three TextBoxes and I want the TextBoxes to be part of a control array called 'mytext', I declare my control array in a module as follows:
Module Module1
Public mytext() As TextBox = {Form1.TextBox1, Form1.TextBox2, Form1.TextBox3}
End Module
And, I use the TextBoxes from the control array as follows:
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
mytext(0).Text = "Hello"
mytext(1).Text = "Hi"
mytext(2).Text = "There"
End Sub
End Class
You can even loop through the control array, like you could in VB6:
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
For i As Integer = 0 To 2
mytext(i).Text = i + 1
Next
End Sub
End Class
The beauty of using a module is that the TextBoxes do not even need to be in the same form.
With Winforms, you could do this:
myForm.Controls _
.OfType(Of TextBox) _
.OrderBy(Function(c) c.Name) _
.Where(Function(c) c.Name.StartsWith("somePrefix")) _
.ToArray()
On your form you would name your textboxes somePrefix1, somePrefix2, etc.
Here is an old article but it could give you more information. The top method is super easy.
Your Form, or PanelControl, or anything else that can contain child controls will have a Property called Controls.
You can loop through all of the text boxes in a control by using
'Create a List of TextBoxes, like an Array but better
Dim myTextBoxControls As New List
For Each uxControl As UserControl in MyFormName.Controls
If TypeOf(uControl) is TextBox
myTextBoxControls.Add(uControl)
End IF
Next
Now you have your iterate-able collection you can work with.
You can access a TextBoxes value with the EditValue property.
After looking at what you're trying to do a little further.
You probably want to name all of your controls with a Prefix, let's say abc for now.
For Each uxControl As UserControl in MyFormName.Controls
If TypeOf(uControl) is TextBox Then
Dim tbControl As TextBox = DirectCast(uControl, TextBox)
If tbControl.Name.StartsWith("abc") Then
tbControl.EditValue = "the Value you want to initialize"
End If
End If
Next
So this is one of the features that did not make the transition to VB.NET -- exactly :-( However, you can accomplish much of what you would have done in VB6 with two different mechanisms in .NET: Looping through the controls collection and handling control events.
Looping Through the Controls Collection
In VB.NET every form and control container has a controls collection. This is a collection that you can loop through and then do an operation on the control like set the value.
Dim myTxt As TextBox
For Each ctl As Control In Me.Controls
If TypeOf ctl Is TextBox Then
myTxt = CType(ctl, TextBox)
myTxt.Text = "something"
End If
Next
In this code sample you iterate over the controls collection testing the type of the returned object. If you find a textbox, cast it to a textbox and then do something with it.
Handling Control Events
You can also handle events over multiple controls with one event handler like you would have using the control array in VB6. To do this you will use the Handles keyword.
Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged, TextBox2.TextChanged, TextBox3.TextChanged
Dim myTxt As TextBox = CType(sender, TextBox)
MessageBox.Show(myTxt.Text)
End Sub
The key here is the Handles keyword on the end of the event handler. You separate out the various controls that you want to handle and the event by using a comma. Make sure that you are handling controls that have the same event declaration. If you ever wondered what sender was for on every event well here's one of the uses for it. Cast the sender argument to the type of control that you are working with and assign it to a local variable. You will then be able to access and manipulate the control that fired the event just like you would have in VB6 if you specified and index to the array.
Using these two techniques you can replicate the functionality of control arrays in VB6. Good luck.
Private Sub Button3_Click(sender As System.Object, e As System.EventArgs) Handles Button3.Click
Dim a() As Control = GetControls("textbox")
For Each c As TextBox In a
c.Text = c.Name
Next
End Sub
Private Function GetControls(typeOfControl As String) As Control()
Dim allControls As New List(Of Control)
'this loop will get all the controls on the form
'no matter what the level of container nesting
'thanks to jmcilhinney at vbforums
Dim ctl As Control = Me.GetNextControl(Me, True)
Do Until ctl Is Nothing
allControls.Add(ctl)
ctl = Me.GetNextControl(ctl, True)
Loop
'now return the controls you want
Return allControls.OrderBy(Function(c) c.Name). _
Where( _
Function(c) (c.GetType.ToString.ToLower.Contains(typeOfControl.ToLower) AndAlso _
c.Name.Contains("Box")) _
).ToArray()
End Function

Search ListBox elements in VB.Net

I'm migrating an application from VB6 to VB.Net and I found a change in the behavior of the ListBox and I'm not sure of how to make it equal to VB6.
The problem is this:
In the VB6 app, when the ListBox is focused and I type into it, the list selects the element that matches what I type. e.g. If the list contains a list of countries and I type "ita", "Italy" will be selected in the listbox.
The problem is that with the .Net version of the control if I type "ita" it will select the first element that starts with i, then the first element that starts with "t" and finally the first element that starts with "a".
So, any idea on how to get the original behavior? (I'm thinking in some property that I'm not seeing by some reason or something like that)
I really don't want to write an event handler for this (which btw, wouldn't be trivial).
Thanks a lot!
I shared willw's frustration. This is what I came up with. Add a class called ListBoxTypeAhead to your project and include this code. Then use this class as a control on your form. It traps keyboard input and moves the selected item they way the old VB6 listbox did. You can take out the timer if you wish. It mimics the behavior of keyboard input in Windows explorer.
Public Class ListBoxTypeAhead
Inherits ListBox
Dim Buffer As String
Dim WithEvents Timer1 As New Timer
Private Sub ListBoxTypeAhead_KeyDown(sender As Object, _
e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
Select Case e.KeyCode
Case Keys.A To Keys.Z, Keys.NumPad0 To Keys.NumPad9
e.SuppressKeyPress = True
Buffer &= Chr(e.KeyValue)
Me.SelectedIndex = Me.FindString(Buffer)
Timer1.Start()
Case Else
Timer1.Stop()
Buffer = ""
End Select
End Sub
Private Sub ListBoxTypeAhead_LostFocus(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.LostFocus
Timer1.Stop()
Buffer = ""
End Sub
Public Sub New()
Timer1.Interval = 2000
End Sub
Private Sub Timer1_Tick(sender As Object, e As System.EventArgs) Handles Timer1.Tick
Timer1.Stop()
Buffer = ""
End Sub
End Class
As you probably know, this feature is called 'type ahead,' and it's not built into the Winform ListBox (so you're not missing a property).
You can get the type-ahead functionality on the ListView control if you set its View property to List.
Public Function CheckIfExistInCombo(ByVal objCombo As Object, ByVal TextToFind As String) As Boolean
Dim NumOfItems As Object 'The Number Of Items In ComboBox
Dim IndexNum As Integer 'Index
NumOfItems = objCombo.ListCount
For IndexNum = 0 To NumOfItems - 1
If objCombo.List(IndexNum) = TextToFind Then
CheckIfExistInCombo = True
Exit Function
End If
Next IndexNum
CheckIfExistInCombo = False
End Function