Click here to Skip to main content
11,484,941 members (78,795 online)
Click here to Skip to main content

Autocomplete Menu

, 19 Mar 2015 LGPL3 193.6K 16.4K 338
Rate this:
Please Sign up or sign in to vote.
Customizable autocomplete menu for RichTextBox, TextBox and other controls

 

Introduction

We all use VisualStudio's autocomplete menu, aka IntelliSense. This is very useful, is not it? Unfortunately, .NET FW does not contain built-in component for autocomplete menu. The proposed control fills this gap.

AutocompleteMenu allows you to easily embed a drop-down hints into any TextBox or RichTextBox on your form.

Implementation

The component contains several classes. Below summarizes the main classes and their functions:

AutocompleteMenu - main component of which contains the basic functions. It subscribes to the events of TextBox, looks for suitable variants, shows a drop-down menu and inserts new text into textbox.

Below are basic properties of the AutocompleteMenu:

  • AllowTabKey - Allows TAB for select menu item.
  • AppearInterval - Interval of menu appear (ms).
  • ImageList - Image list used for items.
  • Items - list of text of menu items (simplest variant of usage of AutocompleteMenu).
  • MaximumSize - Maximum size of popup menu.
  • MinFragmentLength - Minimum fragment length for menu appearing. AutocompleteMenu appears only if current fragment around caret has no less then MinFragmentLength symbols.
  • SearchPattern - Regex pattern for serach fragment around caret.

AutocompleteMenuHost - visual component that derived from ToolStripDropDown. This control allows you to display the menu without losing focus on the main form.

AutocompleteListView - visual component that inherited from UserControl. With GDI+, it draws the items of the drop-down menu. This component is similar to ListView but it allows you to display a large number of elements with a good performance.

AutocompleteItem - menu item. This class contains all the necessary information about menu item. You can extend menu features, inheriting your elements from AutocompleteItem and overriding its virtual methods. Below are basic properties of AutocompleteItem:

  • Text - text for inserting into textbox.
  • MenuText - this text will displayed in popup menu.
  • ImageIndex - index of image for this item.
  • ToolTipTitle - title for tooltip. If ToolTipTitle is null, tooltip will not appear for this item.
  • ToolTipText - text of tooltip.
  • Tag - you can store any data here.

Below are some methods you can override:

  • GetTextForReplace - returns inserting text. You can dynamically change inserting text. For example, you can insert current date.
  • Compare - this method defines will this item visible in menu or not. By default this method make visible only items begin with given fragment. But you can override this behaviour. For example, you can compare by substring, or make fuzzy comparison.
  • OnSelected - this method is called when text was inserted in textbox. You can make here some additional operations with text. For example, you can move caret into some position.

The library also contains a few useful classes derived from AutocompleteItem: SnippetAutocompleteItem (can be used for inserting of code snippets), MethodAutocompleteItem (can be used for inserting of method name after dot), SubstringAutocompleteItem (compares text by substring), MulticolumnAutocompleteItem (draws multicolumn menu).

Using the code

Easy usage:

1) Throw AutocompleteMenu component on your form.

2) Type text of the menu items in AutocompleteMenu.Items:

 

3) Set the AutocompleteMenu property of your TextBox:

4) That's all folks Smile | :)

Advanced usage:

1) Throw AutocompleteMenu component on your form.

2) Create a list of items, and add to the menu, using the methods SetAutocompleteItems() or AddItem(). For example:

string[] snippets = { "if(^)\n{\n}", "if(^)\n{\n}\nelse\n{\n}", "for(^;;)\n{\n}", "while(^)\n{\n}", "do${\n^}while();", "switch(^)\n{\n\tcase : break;\n}" };

private void BuildAutocompleteMenu()
{
    var items = new List<AutocompleteItem>();

    foreach (var item in snippets)
        items.Add(new SnippetAutocompleteItem(item) { ImageIndex = 1 });

    //set as autocomplete source
    autocompleteMenu1.SetAutocompleteItems(items);
}

Also, you can add own items, inherited from AutocompleteItem. For example:

internal class EmailSnippet : AutocompleteItem
{
    public EmailSnippet(string email): base(email)
    {
        ImageIndex = 0;
        ToolTipTitle = "Insert email:";
        ToolTipText = email;
    }

    public override CompareResult Compare(string fragmentText)
    {
        if (fragmentText == Text)
            return CompareResult.VisibleAndSelected;
        if (fragmentText.Contains("@"))
            return CompareResult.Visible;
        return CompareResult.Hidden;
    }
}

More details see the example AdvancedSample of demo application.

Shortcuts:

You can use following shortcuts:

  • Ctrl+Space - forcibly opens AutocompleteMenu.
  • Up, Down, PgUp, PgDown - navigates across menu.
  • Enter, Tab, DblClick on the item - inserts selected item into text (Tab works only if AllowTabKey is true).
  • Esc - closes menu.

Note that these keys are working, despite the fact that the focus is in the textbox.

Item's tooltip appears if you click on the item.

Custom ListView

You can use the custom controls for displaying AutocompleteMenu (like ListView, ListBox, DataGridView, TreeView, etc). For this, create own control (derived from Control) and implement interface IAutocompleteListView. More details see in CustomListViewSample.

Dynamic context menu

It is frequently necessary that the menu display not a fixed set of items, but was changing dynamically, depending on the text. This task can be solved.

Note that method SetAutocompleteItems() of menu takes IEnumerable as collection of displayed items.

So, you can do not generate a list of items at the start of the program, and generate it dynamically at the time of the call the enumerator from the menu.

The following code demonstrates this idea:

    autocompleteMenu1.SetAutocompleteItems(new DynamicCollection(tb));
    ....

    internal class DynamicCollection : IEnumerable<AutocompleteItem>
    {
        public IEnumerator<AutocompleteItem> GetEnumerator()
        {
            return BuildList().GetEnumerator();
        }

        private IEnumerable<AutocompleteItem> BuildList()
        {
            //find all words of the text
            var words = new Dictionary<string, string>();
            foreach (Match m in Regex.Matches(tb.Text, @"\b\w+\b"))
                words[m.Value] = m.Value;

            //return autocomplete items
            foreach(var word in words.Keys)
                yield return new AutocompleteItem(word);
        }
    }

Fully implemented sample see in DynamicMenuSample.

Compatibility

Autocomplete menu is compatible with TextBox, RichTextBox, MaskedTextBox, FastColoredTextBox[^] and other controls derived from TextBoxBase.

Also, Autocomplete Menu is compatible with any control supports following properties and methods:

  • string SelectedText{get;set;}
  • int SelectionLength{get;set;}
  • int SelectionStart{get;set;}
  • Point GetPositionFromCharIndex(int charPos)

Even if your control do not support these methods, you can create own wrapper for it. For this, you must create own wrapper class and implement there interface ITextBoxWrapper.

Below described methods and properties of ITextBoxWrapper:

    public interface ITextBoxWrapper
    {
        Control TargetControl { get; }
        string Text { get; }
        string SelectedText { get; set; }
        int SelectionLength { get; set; }
        int SelectionStart { get; set; }
        Point GetPositionFromCharIndex(int pos);
        event EventHandler LostFocus;
        event ScrollEventHandler Scroll;
        event KeyEventHandler KeyDown;
        event MouseEventHandler MouseDown;
    }

So, when you made wrapper you can simply attach AutocompleteMenu to your control. Something like this:

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

	    //attach myControl1 to autocompleteMenu1
            autocompleteMenu1.TargetControlWrapper = new MyControlWrapper(myControl1);
        }
    }

    internal class MyControlWrapper : ITextBoxWrapper
    {
        private MyControl tb;

        public MyControlWrapper(MyControl tb)
        {
            this.tb = tb;
        }

	//here we implement ITextBoxWrapper
	.....
    }

Samples

Demo application contains several samples:

SimplestSample - shows how to use the control by simplest way.

CustomItemSample - shows how to create own class derived from AutocompleteItem.

AdvancedSample - shows how to create custom autocomplete menu with keywords, snippets, method suggestions, text correctors etc.

ExtraLargeSample - demonstrates performance of the component with extra large list of menu items (one million).

ComboboxSample - shows how to create analog of Combobox, but with very large dropdown list and with searching by substring.

MulticolumnSample - shows how to make multicolumn autocomplete menu:

CustomListViewSample - shows how to make custom ListView, hosted in autocomplete menu:

DynamicMenuSample - this example shows how to create dynamic context-sensitive autocomplete menu.

DataGridViewSample - shows how to attach AutocompleteMenu to DataGridView:

History

13 Apr 2012 - First release.

21 Apr 2012 - The control is refactored. Added support of the FastColoredTextBox[^] and other controls.

9 May 2012 - The control is refactored. Some samples were added.

3 Dec 2014 - Property Colors was added.

8 Feb 2015 - Small bugs were fixed.

19 Mar 2015 - Small bugs were fixed.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)

Share

About the Author

Pavel Torgashov
Software Developer Freelancer
Ukraine Ukraine
I am Pavеl Tоrgаshоv, and I live in Kyiv, Ukraine.
I've been developing software since 1998.
Main activities: processing of large volumes of data, statistics, computer vision and graphics.

My contact email is p_torgashov[at]ukr.net
Follow on   LinkedIn

Comments and Discussions

 
GeneralRe: How do I attach autocomplete menu to a dynamically created FCTB? Pin
Member 802152728-Dec-12 20:13
memberMember 802152728-Dec-12 20:13 
BugNon-flexible Pin
VitekST27-Dec-12 5:59
memberVitekST27-Dec-12 5:59 
GeneralRe: Non-flexible Pin
Pavel Torgashov28-Dec-12 10:57
mvpPavel Torgashov28-Dec-12 10:57 
GeneralRe: Non-flexible Pin
VitekST29-Dec-12 1:21
memberVitekST29-Dec-12 1:21 
GeneralRe: Non-flexible [modified] Pin
Pavel Torgashov29-Dec-12 4:07
mvpPavel Torgashov29-Dec-12 4:07 
GeneralRe: Non-flexible Pin
VitekST29-Dec-12 7:36
memberVitekST29-Dec-12 7:36 
Questionproblem when disabled and re-enable component Pin
nguyenbinh074-Dec-12 6:48
membernguyenbinh074-Dec-12 6:48 
GeneralThis component is VERY GOOD Pin
VitekST19-Nov-12 6:08
memberVitekST19-Nov-12 6:08 
QuestionBUG Pin
Larsbefree12-Nov-12 10:43
memberLarsbefree12-Nov-12 10:43 
AnswerRe: BUG Pin
Pavel Torgashov12-Nov-12 10:55
mvpPavel Torgashov12-Nov-12 10:55 
GeneralRe: BUG Pin
Larsbefree12-Nov-12 12:00
memberLarsbefree12-Nov-12 12:00 
BugError on DropDown Pin
HansiHermann5-Nov-12 11:16
memberHansiHermann5-Nov-12 11:16 
GeneralRe: Error on DropDown Pin
HansiHermann7-Nov-12 9:23
memberHansiHermann7-Nov-12 9:23 
GeneralRe: Error on DropDown Pin
Pavel Torgashov7-Nov-12 9:50
mvpPavel Torgashov7-Nov-12 9:50 
I tried to call this error, but it did not appear...
Can you give me example where this error appeared?
AnswerRe: Error on DropDown Pin
HansiHermann9-Jan-13 9:40
memberHansiHermann9-Jan-13 9:40 
GeneralRe: Error on DropDown Pin
Pavel Torgashov9-Jan-13 21:00
memberPavel Torgashov9-Jan-13 21:00 
GeneralRe: Error on DropDown Pin
HansiHermann10-Jan-13 10:24
memberHansiHermann10-Jan-13 10:24 
QuestionHow to use this autocomplete in WPF or this can't be used for WPF textbox Pin
Vikram_1-Nov-12 22:46
memberVikram_1-Nov-12 22:46 
AnswerRe: How to use this autocomplete in WPF or this can't be used for WPF textbox Pin
Pavel Torgashov2-Nov-12 7:26
mvpPavel Torgashov2-Nov-12 7:26 
GeneralRe: How to use this autocomplete in WPF or this can't be used for WPF textbox Pin
SplitOS29-Mar-13 6:49
memberSplitOS29-Mar-13 6:49 
QuestionWhite space Pin
Larsbefree30-Oct-12 18:23
memberLarsbefree30-Oct-12 18:23 
AnswerRe: White space Pin
Pavel Torgashov2-Nov-12 7:35
mvpPavel Torgashov2-Nov-12 7:35 
QuestionAutocomplete Menu Pin
Larsbefree30-Oct-12 18:18
memberLarsbefree30-Oct-12 18:18 
GeneralMy vote of 5 Pin
Saumitra Kumar Paul27-Oct-12 8:38
memberSaumitra Kumar Paul27-Oct-12 8:38 
GeneralMy vote of 5 Pin
bubifengyun18-Oct-12 2:32
memberbubifengyun18-Oct-12 2:32 
GeneralMy vote of 5 Pin
SachinDakle9-Oct-12 1:42
memberSachinDakle9-Oct-12 1:42 
GeneralMy vote of 5 Pin
BigWorld8-Oct-12 18:08
memberBigWorld8-Oct-12 18:08 
GeneralMy vote of 4 Pin
javadadabi8-Oct-12 9:43
memberjavadadabi8-Oct-12 9:43 
GeneralMy vote of 4 Pin
samthec8-Oct-12 9:22
membersamthec8-Oct-12 9:22 
GeneralRe: My vote of 4 Pin
Pavel Torgashov8-Oct-12 9:47
mvpPavel Torgashov8-Oct-12 9:47 
GeneralRe: My vote of 4 Pin
samthec20-May-13 9:54
membersamthec20-May-13 9:54 
GeneralMy vote of 5 Pin
Balaji Manoharan8-Oct-12 1:06
memberBalaji Manoharan8-Oct-12 1:06 
Question+5 wonderful example of WinForms control extension Pin
BillWoodruff7-Oct-12 21:36
memberBillWoodruff7-Oct-12 21:36 
QuestionA question about this great control Pin
melance424-Oct-12 6:50
membermelance424-Oct-12 6:50 
AnswerRe: A question about this great control Pin
Pavel Torgashov4-Oct-12 7:03
mvpPavel Torgashov4-Oct-12 7:03 
GeneralRe: A question about this great control Pin
Member 101459898-Mar-14 4:39
memberMember 101459898-Mar-14 4:39 
QuestionRequesting little change help Pin
Vinay iGATE2-Oct-12 21:57
memberVinay iGATE2-Oct-12 21:57 
AnswerRe: Requesting little change help Pin
Pavel Torgashov2-Oct-12 23:22
mvpPavel Torgashov2-Oct-12 23:22 
QuestionBug & Feature-Request Pin
HansiHermann1-Oct-12 6:47
memberHansiHermann1-Oct-12 6:47 
AnswerRe: Bug & Feature-Request Pin
Pavel Torgashov1-Oct-12 10:02
mvpPavel Torgashov1-Oct-12 10:02 
GeneralRe: Bug & Feature-Request Pin
HansiHermann1-Oct-12 13:47
memberHansiHermann1-Oct-12 13:47 
GeneralRe: Bug & Feature-Request Pin
Pavel Torgashov1-Oct-12 20:56
mvpPavel Torgashov1-Oct-12 20:56 
GeneralRe: Bug & Feature-Request Pin
HansiHermann1-Oct-12 21:20
memberHansiHermann1-Oct-12 21:20 
GeneralRe: Bug & Feature-Request Pin
Pavel Torgashov2-Oct-12 1:42
mvpPavel Torgashov2-Oct-12 1:42 
GeneralRe: Bug & Feature-Request Pin
HansiHermann2-Oct-12 6:16
memberHansiHermann2-Oct-12 6:16 
GeneralMy vote of 5 Pin
HansiHermann1-Oct-12 1:19
memberHansiHermann1-Oct-12 1:19 
QuestionCan this be used in Silverlight 4 application? Pin
bond35217-Sep-12 10:56
memberbond35217-Sep-12 10:56 
AnswerRe: Can this be used in Silverlight 4 application? Pin
Pavel Torgashov17-Sep-12 20:07
mvpPavel Torgashov17-Sep-12 20:07 
GeneralMy vote of 5 Pin
Lasitha Wattaladeniya5-Aug-12 21:15
memberLasitha Wattaladeniya5-Aug-12 21:15 
GeneralMy vote of 4 Pin
masoodmoo6-Jul-12 3:27
membermasoodmoo6-Jul-12 3:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150520.1 | Last Updated 19 Mar 2015
Article Copyright 2012 by Pavel Torgashov
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid