Link to home
Start Free TrialLog in
Avatar of brian_leighty
brian_leighty

asked on

HELP!!....I have created a user interface to a SQL database using VB.NET....I have a combobox that I would like to autocomplete using the valuse from a specific field...

When the form loads the combobox throughout the form load with values from there specific fields...(ex. states go in cbcuststate2)
I have one combo that fills with all the customer names in the databases...I want my users to be able to type in the first letter and the combobox either autocomplete per letter typed...or a dropdown happend with all the customer names that match the letters typed.....


Thank You Very Much...
Brian
Avatar of amyhxu
amyhxu

Here's the autocomplete combo example: http://www.freevbcode.com/ShowCode.asp?ID=7007

Here's the autocomplete combo with auto expand feature I modified from the example above, and it's probably a better choice for your requirement:
https://www.experts-exchange.com/questions/21379445/Custom-ComboBox-Problem.html
Avatar of brian_leighty

ASKER


How do I use this code.....I cannot get it to work...



Here you go. It worked on my computer, hopefully it will work on yours. If your items contains characters other than numbers, letters and space, you'll need to modify this a little bit. If you are having problem with this, let me know.

Option Strict On
Option Explicit On

Imports System.Windows.Forms

Public Class AutoCompleteCombo
    Inherits ComboBox
    Private mResetOnClear As Boolean = False

    Protected Overrides Sub RefreshItem(ByVal index As Integer)
        MyBase.RefreshItem(index)
    End Sub

    Protected Overrides Sub SetItemsCore(ByVal items As System.Collections.IList)
        MyBase.SetItemsCore(items)
    End Sub

    Public Shadows Sub KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles MyBase.KeyPress
        Dim intIndex As Integer
        Dim strEntry As String

        Me.DroppedDown = True

        If Char.IsControl(e.KeyChar) Then
            If MyBase.SelectionStart <= 1 Then
                If mResetOnClear Then
                    MyBase.SelectedIndex = 0
                    MyBase.SelectAll()
                Else
                    MyBase.Text = String.Empty
                    MyBase.SelectedIndex = -1
                    MyBase.SelectedIndex = -1
                End If
                e.Handled = True
                Exit Sub
            End If
            If MyBase.SelectionLength = 0 Then
                strEntry = MyBase.Text.Substring(0, MyBase.Text.Length - 1)
            Else
                strEntry = MyBase.Text.Substring(0, MyBase.SelectionStart - 1)
            End If
        ElseIf (Not Char.IsLetterOrDigit(e.KeyChar)) And (Not Char.IsWhiteSpace(e.KeyChar)) Then  '< 32 Or KeyAscii > 127 Then
            Exit Sub
        Else
            If MyBase.SelectionLength = 0 Then
                strEntry = UCase(MyBase.Text & e.KeyChar)
            Else
                strEntry = MyBase.Text.Substring(0, MyBase.SelectionStart) & e.KeyChar
            End If
        End If

        intIndex = MyBase.FindString(strEntry)

        If intIndex <> -1 Then
            MyBase.SelectedIndex = intIndex
            MyBase.SelectionStart = strEntry.Length
            MyBase.SelectionLength = MyBase.Text.Length - MyBase.SelectionStart
        End If
        e.Handled = True
        Exit Sub
    End Sub

    Public Property ResetOnClear() As Boolean
        Get
            Return mResetOnClear
        End Get
        Set(ByVal Value As Boolean)
            mResetOnClear = Value
        End Set
    End Property

End Class
Avatar of Bob Learned
AutoCompletion class:

Imports System.Runtime.InteropServices

Public Class AutoComplete : Implements IDisposable

  ' HKEY_CLASSES_ROOT\Interface\{00000101-0000-0000-C000-000000000046}\IEnumString
  <ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000101-0000-0000-C000-000000000046")> _
  Private Interface IEnumString

    Function [Next](ByVal celt As Integer, ByVal rgelt() As String, ByRef pceltFetched As Integer) As Integer

    Function Skip(ByVal celt As Integer) As Integer

    Function Reset() As Integer

    Sub Clone(ByRef ppenum As IEnumString)

  End Interface 'IEnumString'


  <ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("EAC04BC0-3791-11D2-BB95-0060977B464C")> _
  Private Interface IAutoComplete

    Function Init(ByVal hwndEdit As IntPtr, _
      <MarshalAs(UnmanagedType.IUnknown)> ByVal punkACL As Object, _
      ByVal pwszRegKeyPath As String, _
      ByVal pwszQuickComplete As String) As Int32

    ' We must use <PreserveSig()> otherwise after using
    ' autocomplete, fields will not return the next time.

    <PreserveSig()> _
    Function Enable(<[In]()> ByVal fEnable As Boolean) As Boolean

    <PreserveSig()> _
    Function SetOptions(<[In]()> ByVal dwFlag As UInt32) As Integer

    <PreserveSig()> _
    Function GetOptions(<Out()> ByRef pdwFlag As UInt32) As Integer

  End Interface 'IAutoComplete.


  Private Enum ShowOptions
    None = 0
    AutoSuggest = &H1
    AutoAppend = &H2
    Search = &H4
    FilterPrefixes = &H8
    UseTab = &H10
    UpDownKeyDropsList = &H20
    RightToLeft = &H40
  End Enum 'ShowOptions'

  Private _enabled As Boolean
  Private _autoComp As Type
  Private IAutoComp As IAutoComplete


  Private Class EnumString : Implements UCOMIEnumString

    ' UCOMIEnumString is the same as the IEnumString interface
    ' see more at Msdn on http://msdn.microsoft.com/library/d...mi_d2l_89uv.asp

    Private _strArray As ArrayList
    Private _pos As Integer = 0


    Public Property Array() As ArrayList
      Get
        Return _strArray
      End Get
      Set(ByVal Value As ArrayList)
        _strArray = Value
      End Set
    End Property 'Array'


    Public Function [Next](ByVal celt As Integer, ByVal rgelt As String(), _
      ByRef pceltFetched As Integer) As Integer Implements UCOMIEnumString.Next

      Dim retval As Integer = 1

      pceltFetched = 0
      While Not _pos = _strArray.Count AndAlso Not pceltFetched = celt
        rgelt(pceltFetched) = _strArray(_pos)
        pceltFetched += 1
        _pos += 1
      End While

      If Not pceltFetched.CompareTo(celt) = -1 Then
        retval = 0
      End If

      Return retval

    End Function


    Public Function Skip(ByVal celt As Integer) As Integer Implements UCOMIEnumString.Skip

      Dim retval As Integer = 1
      _pos += celt

      If Not _pos = _strArray.Count Then
        retval = 0
      End If

      Return retval

    End Function 'Skip'


    Public Function Reset() As Integer Implements UCOMIEnumString.Reset

      _pos = 0

      Return _pos

    End Function 'Reset'


    Public Sub Clone(ByRef ppenum As UCOMIEnumString) Implements UCOMIEnumString.Clone

      ' create a Clone of this Class
      ppenum = DirectCast(Me, EnumString)

    End Sub 'Clone'

  End Class 'EnumString'


  Public Sub New(ByVal handleEdit As IntPtr, ByVal listWords As ArrayList, Optional ByVal registryPath As String = "", Optional ByVal quickComplete As String = "")

    Dim iEnumList As New EnumString
    iEnumList.Array = listWords

    _autoComp = Type.GetTypeFromCLSID(New Guid("{00BB2763-6A77-11D0-A535-00C04FD7D062}"))

    IAutoComp = DirectCast(Activator.CreateInstance(_autoComp), _
      IAutoComplete)

    ' Initialize IAutoComplete.
    IAutoComp.Init(handleEdit, iEnumList, registryPath, quickComplete)

    ' Set IAutoComplete Options.
    IAutoComp.SetOptions(Convert.ToUInt32(ShowOptions.AutoSuggest Or _
      ShowOptions.UpDownKeyDropsList Or ShowOptions.AutoAppend))

    ' Enable IAutoComplete.
    IAutoComp.Enable(True)

  End Sub 'New'


  Public Sub Dispose() Implements System.IDisposable.Dispose

    Marshal.ReleaseComObject(IAutoComp)

  End Sub 'Dispose'


  Public Property Enabled() As Boolean
    Get
      Return _enabled
    End Get
    Set(ByVal Value As Boolean)
      _enabled = Value
      If Value Then
        IAutoComp.SetOptions(Convert.ToUInt32(ShowOptions.AutoSuggest Or ShowOptions.UpDownKeyDropsList Or ShowOptions.AutoAppend))
      Else
        IAutoComp.SetOptions(Convert.ToUInt32(ShowOptions.None))
      End If
    End Set
  End Property 'Enabled'

End Class 'AutoComplete'

Usage:

      Dim listWords As New ArrayList
      listWords.Add("Green")
      listWords.Add("Red")
      listWords.Add("Yellow")
      listWords.Add("Blue")
      listWords.Add("Magenta")
      listWords.Add("Maroon")
      listWords.Add("Cyan")

      Dim completer As New AutoComplete(Me.TextBox1.Handle, listWords)

Bob
I have know Idea how to use this code it looks way to advanced for me.....

Please Explain farther....I tried inserting but did not work..

Is there anyway the combobox has to be set up for this to work...

thanks
Instead of dragging one generic combobox from the toolbox, you should declare the autocomplete combo in code:

e.g.
First add this class to your project, then in your form

Dim cb As AutoCompleteCombo

   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        cb = New AutoCompleteCombo
        Me.Controls.Add(cb)
        cb.Location = New System.Drawing.Point(100, 100)
        cb.Size = New System.Drawing.Size(300, 24)
        cb.TabIndex = 1
        ...

   End Sub
Brian,
Who are you talking to about being too advanced?  If it was me, and you need this for a combo box, then you need this:

  Private Declare Function FindWindowEx _
    Lib "user32" Alias "FindWindowExA" _
    (ByVal hWnd1 As IntPtr, ByVal hWnd2 As IntPtr, _
    ByVal lpsz1 As String, ByVal lpsz2 As String) As IntPtr

  Public Function ComboBoxEditHandle(ByVal comboCurrent As ComboBox) As IntPtr

    ' Get the handle of the inner Edit control.
    Dim editHandle As IntPtr = FindWindowEx(comboCurrent.Handle, IntPtr.Zero, vbNullString, vbNullString)

    Return editHandle

  End Function 'ComboBoxEditHandle'

Usage:
Dim listWords As New ArrayList
      listWords.Add("Green")
      listWords.Add("Red")
      listWords.Add("Yellow")
      listWords.Add("Blue")
      listWords.Add("Magenta")
      listWords.Add("Maroon")
      listWords.Add("Cyan")

      Dim completer As New AutoComplete(ComboBoxEditHandle(Me.ComboBox1), listWords)

Bob

Adding items to or setting datasource for the AutoCompleteCombo uses the same code you used for populating a normal ComboBox.
BTW, the AutoComplete class binds an edit control to the Internet Explorer-style auto-completion.

Bob
LearnedOne I really cannot get your code to work...

I made a class and changed the combobox to use that class and I get an error with listwords in your class...
it says that listwords is not defined
Did you get this code, too?

Dim listWords As New ArrayList
listWords.Add("Green")
listWords.Add("Red")
listWords.Add("Yellow")
listWords.Add("Blue")
listWords.Add("Magenta")
listWords.Add("Maroon")
listWords.Add("Cyan")

Bob
Amyhxu your code works perfect but when I hit the enter key it backspaces and if nothing exist then I get an error...currently debugging to find out where....
well the items that I'm adding come from a SQL field....ignore my ignorance but does the "listwords.add" add items to the combobox manually or from a field....


just for shits and giggles where would I put the listwords code at....usage code
Dim listWords As New ArrayList

      Dim completer As New AutoComplete(ComboBoxEditHandle(Me.ComboBox1), listWords)

This is the list of words that are to be used for the AutoComplete.

Bob
so if it type in "M" i get a "magenta" in the box and if I type in "MAR" then it changes to "maroon"

thanks
The list of words that you add to listWords control what is shown in the auto-completion.

Bob
but I need to autocomplete what is in a SQL field.... "customer names"
ASKER CERTIFIED SOLUTION
Avatar of amyhxu
amyhxu

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Also, make sure you are using .NET framework 1.1 and service Pack1.