1

I am trying to have an autocomplete feature for a ToolStripTextBox in a C# winform application

It is what I have tried

   toolStripTextBox1.AutoCompleteMode = AutoCompleteMode.Suggest;
   toolStripTextBox1.AutoCompleteSource = AutoCompleteSource.AllUrl;          

But for it to suggest a URL, I should type the URL from the beginning (e.g. http://en.wikipedia.org/wiki/Machine_learn...)

What I look for is something like Firefox autocomplete feature, as I type a title or part of the URL, it shows me the matching URL. For example after I type Machine_learning in the example above, it should suggests http://en.wikipedia.org/wiki/Machine_learning

Any solution please?

By the way, I found this similar question WinForms | C# | AutoComplete in the Middle of a Textbox?, but it gets a custom source (array of string), however I like to use AutoCompleteSource.AllUrl as autocomplete source. Moreover the mentioned link is about a textbox and I can't use it in a toolbar. what I need is a solution fo toolStripTextBox

Community
  • 1
  • 1
Ahmad
  • 8,811
  • 11
  • 76
  • 141
  • So your actual question is "How do I get autocomplete to suggest partial matches"? – cbr Mar 18 '15 at 13:04
  • In that case you can find your answer here: [WinForms | C# | AutoComplete in the Middle of a Textbox?](http://stackoverflow.com/questions/1437002/winforms-c-sharp-autocomplete-in-the-middle-of-a-textbox) – cbr Mar 18 '15 at 13:10
  • @GrawCube I am reading it, but I am afraid it doesn't get AllUrls as Source, does it? – Ahmad Mar 18 '15 at 13:15

1 Answers1

1

This is the code I used.

You only need to set AutoCompleteCustomSource.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;

namespace System.Windows.Forms
{
    /// <summary>
    /// The partial auto complete text box.
    /// </summary>
    /// <remarks>Set only <seealso href="AutoCompleteCustomSource"/></remarks>
    public class PartialAutoCompleteTextBox : TextBox
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="PartialAutoCompleteTextBox"/> class.
        /// </summary>
        public PartialAutoCompleteTextBox()
        {
            AutoItemWidth = true;
        }

        /// <summary>
        /// Gets or sets a value indicating whether auto item width.
        /// </summary>
        [DefaultValue(true)]
        public bool AutoItemWidth { get; set; }

        /// <summary>
        /// Gets or sets the drop down list.
        /// </summary>
        protected ListBox DropDownList { get; set; }

        /// <summary>
        /// Fire create control.
        /// </summary>
        protected override void OnCreateControl()
        {
            base.OnCreateControl();
            DropDownList = new ListBox
            {
                Left = Left,
                Top = Top + Height,
                Width = Width,
                Visible = false,
            };
            Parent.Controls.Add(DropDownList);
        }

        /// <summary>
        /// Raise an <see cref="System.Windows.Forms.Control.KeyUp" /> event.</summary>
        /// <param name="e"><see cref="System.Windows.Forms.KeyEventArgs" />.</param>
        protected override void OnKeyUp(KeyEventArgs e)
        {
            base.OnKeyUp(e);
            UpdateDropDown();
        }

        /// <summary>
        /// Raise an <see cref="System.Windows.Forms.Control.KeyDown" /> event.</summary>
        /// <param name="e"><see cref="System.Windows.Forms.KeyEventArgs" />.</param>
        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);

            switch (e.KeyCode)
            {
                case Keys.Tab:
                case Keys.Enter:
                    if (DropDownList.Visible == true)
                    {
                        InsertToText(Convert.ToString(DropDownList.SelectedItem));
                        HideDropDown();
                        _beforeText = Text;
                        e.SuppressKeyPress = true;
                    }

                    break;
                case Keys.Escape:
                    if (DropDownList.Visible == true)
                    {
                        HideDropDown();
                    }

                    e.SuppressKeyPress = true;

                    break;
                case Keys.Up:
                    if (DropDownList.Visible == true)
                    {
                        if (DropDownList.SelectedIndex == 0)
                        {
                            Focus();
                        }
                        else if (DropDownList.SelectedIndex > 0)
                        {
                            DropDownList.SelectedIndex--;
                        }

                        e.SuppressKeyPress = true;
                    }

                    break;
                case Keys.Down:
                    if (DropDownList.Visible == true)
                    {
                        if (DropDownList.SelectedIndex < DropDownList.Items.Count - 1)
                        {
                            DropDownList.SelectedIndex++;
                        }
                    }
                    else if (e.Modifiers == Keys.Alt)
                    {
                        ShowDropDown();
                    }

                    break;

            }
        }

        /// <summary>
        /// Checks whether the specified key is an input key or a special key that requires preprocessing.
        /// </summary>
        /// <param name="keyData">The key data.</param>
        /// <returns>A bool.</returns>
        protected override bool IsInputKey(Keys keyData)
        {
            switch (keyData)
            {
                case Keys.Tab:
                    return DropDownList.Visible = true;
            }

            return base.IsInputKey(keyData);
        }

        private void ShowDropDown()
        {
            DropDownList.Visible = true;
            DropDownList.BringToFront();
        }

        private void HideDropDown()
        {
            DropDownList.Visible = false;
        }

        private string _beforeText;

        private void UpdateDropDown()
        {
            if (Text == _beforeText || AutoCompleteCustomSource.Count == 0)
            {
                return;
            }

            _beforeText = Text;

            var matches = AutoCompleteCustomSource.Cast<string>().Where(x => x.IndexOf(Text, StringComparison.OrdinalIgnoreCase) >= 0).ToArray();

            if (matches.Length > 0)
            {
                ShowDropDown();
                DropDownList.SuspendLayout();
                DropDownList.Items.Clear();
                DropDownList.Items.AddRange(matches);

                if (AutoItemWidth == true)
                {
                    SetAutoItemWidth();
                }

                DropDownList.SelectedIndex = 0;
                DropDownList.Height = DropDownList.GetItemHeight(0) * Math.Min(30, matches.Length);
                DropDownList.ResumeLayout();
                Focus();
            }
            else
            {
                HideDropDown();
            }
        }

        private void InsertToText(string selectedItem)
        {
            Text = selectedItem;
            SelectionStart = Text.Length;
        }

        private void SetAutoItemWidth()
        {
            using (var graphics = DropDownList.CreateGraphics())
            {
                var itemWidth = DropDownList.Items.Cast<string>().Min(x => (int)graphics.MeasureString((x) + "_", DropDownList.Font).Width);

                DropDownList.Width = Math.Max(DropDownList.Width, itemWidth + 20); // 20 is scrol bar width
            }
        }
    }
}
Kim Ki Won
  • 1,795
  • 1
  • 22
  • 22