I'm writing a program that at one point implements a TextBox
with autocomplete. Currently, for purpose of simplicity I'm using CustomSource
manually populated by several entries at design time. While autocomplete works fine, I'd like it to make suggestions that don't simply start with the currently entered text, but contain it at any position in the stored choices.
For example, if words "globe", "lobe", and "glide" are the stored options, typing in "gl" correctly suggests both "globe" and "glide".
However, I'd like it to suggest both "globe" and "lobe" when "lob" is typed in. I'm not exactly sure how to approach this.
Has anyone done this before? VB.NET or C# are both fine, as long as I can figure out a proper .NET way to do this.
Cheers! = )
So i was looking for something like this. A TextBox with AutoComplete with a Contains search instead of a StartsWith.
This rendition is from this WinForms | C# | AutoComplete in the Middle of a Textbox?
I was able to make this, here is my version of an autocomplete that uses Contains. I hope everyone finds this usable.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace TowInvoicing
{
//from https://stackoverflow.com/questions/1437002/winforms-c-sharp-autocomplete-in-the-middle-of-a-textbox
public class AutoCompleteTextBox : TextBox
{
private ListBox _listBox;
private bool _isAdded;
private String[] _values;
private String _formerValue = String.Empty;
public AutoCompleteTextBox()
{
InitializeComponent();
ResetListBox();
}
private void InitializeComponent()
{
_listBox = new ListBox();
this.KeyDown += this_KeyDown;
this.KeyUp += this_KeyUp;
}
private void ShowListBox()
{
if (!_isAdded)
{
Parent.Controls.Add(_listBox);
_listBox.Left = Left;
_listBox.Top = Top + Height;
_isAdded = true;
}
_listBox.Visible = true;
_listBox.BringToFront();
}
private void ResetListBox()
{
_listBox.Visible = false;
}
private void this_KeyUp(object sender, KeyEventArgs e)
{
UpdateListBox();
}
private void this_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Enter:
case Keys.Tab:
{
if (_listBox.Visible)
{
Text = _listBox.SelectedItem.ToString();
ResetListBox();
_formerValue = Text;
this.Select(this.Text.Length, 0);
e.Handled = true;
}
break;
}
case Keys.Down:
{
if ((_listBox.Visible) && (_listBox.SelectedIndex < _listBox.Items.Count - 1))
_listBox.SelectedIndex++;
e.Handled = true;
break;
}
case Keys.Up:
{
if ((_listBox.Visible) && (_listBox.SelectedIndex > 0))
_listBox.SelectedIndex--;
e.Handled = true;
break;
}
}
}
protected override bool IsInputKey(Keys keyData)
{
switch (keyData)
{
case Keys.Tab:
if (_listBox.Visible)
return true;
else
return false;
default:
return base.IsInputKey(keyData);
}
}
private void UpdateListBox()
{
if (Text == _formerValue)
return;
_formerValue = this.Text;
string word = this.Text;
if (_values != null && word.Length > 0)
{
string[] matches = Array.FindAll(_values,
x => (x.ToLower().Contains(word.ToLower())));
if (matches.Length > 0)
{
ShowListBox();
_listBox.BeginUpdate();
_listBox.Items.Clear();
Array.ForEach(matches, x => _listBox.Items.Add(x));
_listBox.SelectedIndex = 0;
_listBox.Height = 0;
_listBox.Width = 0;
Focus();
using (Graphics graphics = _listBox.CreateGraphics())
{
for (int i = 0; i < _listBox.Items.Count; i++)
{
if (i < 20)
_listBox.Height += _listBox.GetItemHeight(i);
// it item width is larger than the current one
// set it to the new max item width
// GetItemRectangle does not work for me
// we add a little extra space by using '_'
int itemWidth = (int)graphics.MeasureString(((string)_listBox.Items[i]) + "_", _listBox.Font).Width;
_listBox.Width = (_listBox.Width < itemWidth) ? itemWidth : this.Width;;
}
}
_listBox.EndUpdate();
}
else
{
ResetListBox();
}
}
else
{
ResetListBox();
}
}
public String[] Values
{
get
{
return _values;
}
set
{
_values = value;
}
}
public List<String> SelectedValues
{
get
{
String[] result = Text.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
return new List<String>(result);
}
}
}
}
the list you are search in
try use the condition to get in list or not
stringItemInList.IndexOf("txtwhatyousearchfor",StringComparison.OrdinalIgnoreCase) != -1
if you connect to a database use in you query
parameter LIKE '%txthere%'
Regards
UPDATE
after you comment
The best option I see would be to create your own implementation of IAutoComplete. Here is info on it: http://msdn.microsoft.com/en-us/library/bb776292%28VS.85%29.aspx
Also you can do some searches for some code samples of people creating their own IAutoComplete implementations.
Regards