C#: Autocomplete in a  textbox

trevor1940
trevor1940 used Ask the Experts™
on
Hi
Building on an earlier question

I'm trying to create a Winforms Application

Although related I've split this into 2 questions

I'd like to create an Autocomplete to search   and filter the movies by actor/ person name

I've built Autocomplete in other languages  eg jQuery this is a two step process 1st a list of possible options 2nd  you have an OnSelect action I don't seem to be able to find similar in .Net  so the code bellow is running Loading the  Titles in ListView, if the entire name if correctly typed, with out being able to make a selection

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Windows.Forms;
using MoviesDataModel;

namespace FilmsDB
{
    public partial class Form1 : Form
    {
        public string ImgPath = @"E:\Media\thumbs\Movies\";
        public Form1()
        {
            InitializeComponent();
            TitlesLV.View = View.Details;
            ColumnHeader columnHeader = new ColumnHeader();
            columnHeader.Text = "Film Title";
            columnHeader.TextAlign = HorizontalAlignment.Center;
            columnHeader.Width = -2;

            TitlesLV.Columns.Add(columnHeader);
            LoadMovies();
        }

        private void LoadMovies()
        {
            TitlesLV.Items.Clear();
            using (var context = new MoviesEntities())
            {
                //get a full list of all movies (will return everything from the database)
                var allMovies = context.movies.OrderBy(m => m.title).ToArray();
                foreach(var Movie in allMovies)
                {
                    ListViewItem item = new ListViewItem();
                    item.Text = Movie.title;
                    item.Tag = Movie;
                    TitlesLV.Items.Add(item);
                }

            }
        }

        private void PeopleSearchData(object sender, KeyEventArgs e)
        {
            if (PeopleSearchTxtBox.TextLength >2)
            {
                AutoCompleteStringCollection collection = new AutoCompleteStringCollection();
            using (var context = new MoviesEntities())
            {
                    var People = context.people.AsQueryable().Where(p => p.name.Contains(PeopleSearchTxtBox.Text)).ToList();

                    if(People.Count > 0)
                    {
                        foreach(var Person in People)
                        {
                            collection.Add( Person.name);
                            
                        }
                    }

                    PeopleSearchTxtBox.AutoCompleteMode = AutoCompleteMode.Suggest;
                    PeopleSearchTxtBox.AutoCompleteSource = AutoCompleteSource.CustomSource;
                    PeopleSearchTxtBox.AutoCompleteCustomSource = collection;

                }
            }
        }

        private void TableLayoutPanel1_Paint(object sender, PaintEventArgs e)
        {

        }

        private void TitlesLV_SelectedIndexChanged(object sender, EventArgs e)
        {
            int i = TitlesLV.SelectedIndices[0];
            var  movie = TitlesLV.Items[i].Tag as movie;
            int id = movie.id;
            var PosterPath = ImgPath + id.ToString() + ".jpg";

            if (File.Exists(PosterPath))
            {
                PosterPicBox.Load(PosterPath);
            }
            {

            }
        }

        private void PeopleSearchTxtBox_TextChanged(object sender, EventArgs e)
        {
            using (var context = new MoviesEntities())
            {
                var Movies = context.movies.AsQueryable().Where(m => m.movielinkpersons.Any(p => p.person.name == PeopleSearchTxtBox.Text)).ToList() ;
                TitlesLV.Items.Clear();
                foreach (var Movie in Movies)
                {
                    ListViewItem item = new ListViewItem();
                    item.Text = Movie.title;
                    item.Tag = Movie;
                    TitlesLV.Items.Add(item);
                }

            }
        }
    }
}

Open in new window

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Senior Full Stack Developer
Distinguished Expert 2017
Commented:
If you are using a Winforms app, have a look at the TextBox.AutoCompleteMode Property.
The sample code in the article demonstrates how to use a collection as the auto-complete custom source for a TextBox control:
private void Form1_Load(object sender, EventArgs e)
{
    // Create the list to use as the custom source. 
    var source = new AutoCompleteStringCollection();
    source.AddRange(new string[]
                    {
                        "January",
                        "February",
                        "March",
                        "April",
                        "May",
                        "June",
                        "July",
                        "August",
                        "September",
                        "October",
                        "November",
                        "December"
                    });

    // Create and initialize the text box.
    var textBox = new TextBox
                  {
                      AutoCompleteCustomSource = source,
                      AutoCompleteMode = 
                          AutoCompleteMode.SuggestAppend,
                      AutoCompleteSource =
                          AutoCompleteSource.CustomSource,
                      Location = new Point(20, 20),
                      Width = ClientRectangle.Width - 40,
                      Visible = true
                  };

    // Add the text box to the form.
    Controls.Add(textBox);
}

Open in new window

The code does the following:
  • Uses the AutoCompleteSource property to enable the TextBox control to accept a custom source for its auto-complete behavior.
  • Uses the AutoCompleteCustomSource property to set the custom list of values.
  • Uses the AutoCompleteMode property to set how the auto-complete candidates are displayed.

Author

Commented:
Hi
Thanx for the link In it's self that works and is essentially what I'm doing however it hasn't helped

In order to debug i've disabled the text changed event

Currently the  AutoComplete Suggestion list is being populated but isn't displaying long enough to make a selection
Dirk StraussSenior Full Stack Developer
Distinguished Expert 2017

Commented:
As a test, remove TitlesLV.Items.Clear(); from the PeopleSearchTxtBox_TextChanged event. Also, have a look at what the final value is for PeopleSearchTxtBox.Text that get's sent through after you finish typing.
HTML5 and CSS3 Fundamentals

Build a website from the ground up by first learning the fundamentals of HTML5 and CSS3, the two popular programming languages used to present content online. HTML deals with fonts, colors, graphics, and hyperlinks, while CSS describes how HTML elements are to be displayed.

Author

Commented:
I re enabled the PeopleSearchTxtBox_TextChanged event and added
MessageBox.Show(PeopleSearchTxtBox.Text);

Open in new window


This is fired on each letter

Attempting to Search for "sean connery"

I get to "sean " before "sean Alan"  appears in the text box and their films are added to the listview

In  your app you posted  Typing "j" or "J" you get a choice which stays visible until a selection is made eg "June" then appears in the TxtBox
I don't get this choice however

var People => 107 "sean "
or
var People =>. 3 "kate h"

Open in new window

Dirk StraussSenior Full Stack Developer
Distinguished Expert 2017

Commented:
Perhaps you should make the search term and the field it's matching on, case insensitive (i.e. both lower case). Also, try a like search instead of a == search. If you must have a perfect match, try using something similar to .Equals() on the string instead of == (I'm not too certain of the Lambda syntax right now).

Author

Commented:
OK but how will  changing the  search query  keep the return / available choices visible long enough to pick the correct person?

Secondly this would assume you know the exact spelling of a persons name!
Dirk StraussSenior Full Stack Developer
Distinguished Expert 2017

Commented:
Secondly this would assume you know the exact spelling of a persons name!
Which is why I suggested using a like statement instead of an ==

I am thinking that something (either casing or not an exact match) is causing the Movies to return with nothing (no match) and then not display the suggestions.

Author

Commented:
I Think the list of name options is being displayed very briefly

I'm wondering if I need to code somewhere over than  "private void PeopleSearchData(object sender, KeyEventArgs e)"

List Link example suggests on form load

Author

Commented:
I've solved this by doing the following :

I've moved the AutoComplete code into a method called  on form_load()

There isn't selection event?


PeopleSearchTxtBox_MouseClick Fails I think  because your clicking a list item not the text box the same goes for the Enter key

This Worked
        private void PeopleSearchTxtBox_TextChanged(object sender, EventArgs e)
        {
            if (PeopleSearchTxtBox.AutoCompleteCustomSource.Contains(PeopleSearchTxtBox.Text))
            {
                PeopleSearchData(); // Query 
            }
        }

Open in new window

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial