How to make an auto-complete textbox in a winforms desktop application
Asked Answered
S

6

20

I have a list of words. The list contains about 100-200 text strings (it's names of metro stations actually).

I want to make an auto-complete textbox. For an example, user press 'N' letter, then an (ending of) appropriate option appear (only one option). The ending must be selected.

How to do that?

PS1: I guess, there is a textbox control with a Property something like this:

List<string> AppropriateOptions{/* ... */}

PS2: sorry for my english. If you didn't understand -> ask me and I will try to explain!

Shirleyshirlie answered 7/1, 2011 at 20:21 Comment(0)
A
29

Just in case @leniel's link goes down, here's some code that does the trick:

AutoCompleteStringCollection allowedTypes = new AutoCompleteStringCollection();
allowedTypes.AddRange(yourArrayOfSuggestions);
txtType.AutoCompleteCustomSource = allowedTypes;
txtType.AutoCompleteMode = AutoCompleteMode.Suggest;
txtType.AutoCompleteSource = AutoCompleteSource.CustomSource;
Aufmann answered 13/8, 2013 at 18:49 Comment(3)
Thanks Joel,It worked for me.Can we select the suggestion text with Up and Down Arrow keys.I tried but it didn't allow me.Wolters
@rakesh I haven't worked on winforms for a while now, and I don't remember whether is a "standard" feature or involves extra effort. SorryAufmann
Thank you for providing the gist instead of a link-only answer.Realty
S
6

Use a ComboBox instead of a TextBox. The following example will autocomplete, matching any piece of the text, not just the starting letters.

This should be a complete form, just add your own data source, and data source column names. :-)

using System;
using System.Data;
using System.Windows.Forms;

public partial class frmTestAutocomplete : Form
{

    private DataTable maoCompleteList;
    private const string MC_DISPLAY_COL = "name";
    private const string MC_ID_COL = "id";

    public frmTestAutocomplete()
    {
        InitializeComponent();
    }

    private void frmTestAutocomplete_Load(object sender, EventArgs e)
    {

        maoCompleteList = GetDataTableFromDatabase();
        maoCompleteList.CaseSensitive = false; //turn off case sensitivity for searching

        testCombo.DisplayMember = MC_DISPLAY_COL;
        testCombo.ValueMember = MC_ID_COL;
        testCombo.DataSource = maoCompleteList;
        testCombo.SelectedIndexChanged += testCombo_SelectedIndexChanged;
        testCombo.KeyUp += testCombo_KeyUp;
    }


    private void testCombo_KeyUp(object sender, KeyEventArgs e)
    {
        //use keyUp event, as text changed traps too many other evengts.

        ComboBox oBox = (ComboBox)sender;
        string sBoxText = oBox.Text;

        DataRow[] oFilteredRows = maoCompleteList.Select(MC_DISPLAY_COL + " Like '%" + sBoxText + "%'");

        DataTable oFilteredDT = oFilteredRows.Length > 0
                                ? oFilteredRows.CopyToDataTable()
                                : maoCompleteList;

        //NOW THAT WE HAVE OUR FILTERED LIST, WE NEED TO RE-BIND IT WIHOUT CHANGING THE TEXT IN THE ComboBox.

        //1).UNREGISTER THE SELECTED EVENT BEFORE RE-BINDING, b/c IT TRIGGERS ON BIND.
        oBox.SelectedIndexChanged -= testCombo_SelectedIndexChanged; //don't select on typing.
        oBox.DataSource = oFilteredDT; //2).rebind to filtered list.
        oBox.SelectedIndexChanged += testCombo_SelectedIndexChanged;


        //3).show the user the new filtered list.
        oBox.DroppedDown = true; //this will overwrite the text in the ComboBox, so 4&5 put it back.

        //4).binding data source erases text, so now we need to put the user's text back,
        oBox.Text = sBoxText;
        oBox.SelectionStart = sBoxText.Length; //5). need to put the user's cursor back where it was.


    }

    private void testCombo_SelectedIndexChanged(object sender, EventArgs e)
    {

        ComboBox oBox = (ComboBox)sender;

        if (oBox.SelectedValue != null)
        {
            MessageBox.Show(string.Format(@"Item #{0} was selected.", oBox.SelectedValue));
        }
    }

}

//=====================================================================================================
//      code from frmTestAutocomplete.Designer.cs
//=====================================================================================================
partial class frmTestAutocomplete

{
    /// <summary>
    /// Required designer variable.
    /// </summary>
    private readonly System.ComponentModel.IContainer components = null;

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Windows Form Designer generated code

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this.testCombo = new System.Windows.Forms.ComboBox();
        this.SuspendLayout();
        // 
        // testCombo
        // 
        this.testCombo.FormattingEnabled = true;
        this.testCombo.Location = new System.Drawing.Point(27, 51);
        this.testCombo.Name = "testCombo";
        this.testCombo.Size = new System.Drawing.Size(224, 21);
        this.testCombo.TabIndex = 0;
        // 
        // frmTestAutocomplete
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(292, 273);
        this.Controls.Add(this.testCombo);
        this.Name = "frmTestAutocomplete";
        this.Text = "frmTestAutocomplete";
        this.Load += new System.EventHandler(this.frmTestAutocomplete_Load);
        this.ResumeLayout(false);

    }

    #endregion

    private System.Windows.Forms.ComboBox testCombo;
}
Stonefish answered 11/2, 2017 at 0:31 Comment(0)
H
1

The answer link by Leniel was in vb.net, thanks Joel for your entry. Supplying my code to make it more explicit:

private void InitializeTextBox()
{

    AutoCompleteStringCollection allowedStatorTypes = new AutoCompleteStringCollection();
    var allstatortypes = StatorTypeDAL.LoadList<List<StatorType>>().OrderBy(x => x.Name).Select(x => x.Name).Distinct().ToList();

    if (allstatortypes != null && allstatortypes.Count > 0)
    {
        foreach (string item in allstatortypes)
        {
            allowedStatorTypes.Add(item);
        }
    }

    txtStatorTypes.AutoCompleteMode = AutoCompleteMode.Suggest;
    txtStatorTypes.AutoCompleteSource = AutoCompleteSource.CustomSource;
    txtStatorTypes.AutoCompleteCustomSource = allowedStatorTypes;
}
Hamamelidaceous answered 11/3, 2014 at 18:9 Comment(0)
T
1

Use combo box, sets its datasource or give hard coded entries but set the following properties:

    AutoCompleteMode = Suggest;
    AutoCompleteSource = ListItems;
Tiatiana answered 10/8, 2018 at 11:24 Comment(0)
P
0

You want to set the TextBox.AutoCompleteSource to CustomSource and then add all of your strings to its AutoCompleteCustomSource property, which is a StringCollection. Then you should be good to go.

Parturition answered 7/1, 2011 at 20:29 Comment(0)
M
0

I want to add that the standard autocomplete for TextBox does only work from the beginning of your strings, so if you hit N only strings starting with N will be found. If you want to have something better, you have to use some different control or implement the behavior for yourself (i.e. react on TextChanged Event with some timer to delay execution, than filter your tokenlist searching with IndexOf(inputString) and then set your AutoCompleteSource to the filtered list.

Maroon answered 27/7, 2016 at 9:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.