65.9K
CodeProject 正在变化。 阅读更多。
Home

自动完成菜单

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.89/5 (238投票s)

2012 年 4 月 13 日

LGPL3

5分钟阅读

viewsIcon

947002

downloadIcon

29108

为 RichTextBox、TextBox 及其他控件提供可自定义的自动完成菜单

引言

我们都使用 VisualStudio 的自动完成菜单,也称为 IntelliSense。这个功能非常有用,不是吗?不幸的是,.NET FW 没有内置的自动完成菜单组件。本控件旨在填补这一空白。

AutocompleteMenu 允许您轻松地将下拉提示嵌入到窗体上的任何 TextBoxRichTextBox 中。

实现

该组件包含几个类。下面总结了主要类及其功能

AutocompleteMenu - 主要组件,包含基本功能。它订阅 TextBox 的事件,查找合适的选项,显示下拉菜单并向 textbox 插入新文本。

以下是 AutocompleteMenu 的基本属性

  • AllowTabKey - 允许使用 TAB 键选择菜单项
  • AppearInterval - 菜单出现间隔 (毫秒)
  • ImageList - 用于菜单项的图像列表
  • Items - 菜单项文本列表(使用 AutocompleteMenu 的最简单方式)
  • MaximumSize - 弹出菜单的最大尺寸
  • MinFragmentLength - 菜单出现的最小片段长度。AutocompleteMenu 仅在当前光标周围的片段至少包含 MinFragmentLength 个字符时出现
  • SearchPattern - 用于搜索光标周围片段的正则表达式模式

AutocompleteMenuHost - 派生自 ToolStripDropDown 的可视化组件。此控件允许您在不失去主窗体焦点的情况下显示菜单。

AutocompleteListView - 派生自 UserControl 的可视化组件。它使用 GDI+ 绘制下拉菜单的项。此组件类似于 ListView,但它允许您以良好的性能显示大量元素。

AutocompleteItem - 菜单项。此类包含有关菜单项的所有必要信息。您可以通过继承 AutocompleteItem 并重写其虚拟方法来扩展菜单功能。以下是 AutocompleteItem 的基本属性

  • Text - 要插入 textbox 的文本
  • MenuText - 将显示在弹出菜单中的文本
  • ImageIndex - 此项的图像索引
  • ToolTipTitle - 工具提示的标题。如果 ToolTipTitlenull,则此项不会显示工具提示
  • ToolTipText - 工具提示的文本
  • Tag - 您可以在此处存储任何数据

以下是一些您可以重写的方法

  • GetTextForReplace - 返回要插入的文本。您可以动态更改要插入的文本。例如,您可以插入当前日期。
  • Compare - 此方法定义此项是否在菜单中可见。默认情况下,此方法仅使以给定片段开头的项可见。但您可以覆盖此行为。例如,您可以按子字符串比较,或进行模糊比较。
  • OnSelected - 在文本已插入 textbox 时调用此方法。在这里,您可以对文本进行一些额外的操作。例如,您可以将光标移动到某个位置。

该库还包含几个派生自 AutocompleteItem 的有用类:SnippetAutocompleteItem(可用于插入代码片段)、MethodAutocompleteItem(可用于在点后插入方法名称)、SubstringAutocompleteItem(按子字符串比较文本)、MulticolumnAutocompleteItem(绘制多列菜单)。

Using the Code

简单用法

  1. AutocompleteMenu 组件放置在您的窗体上。
  2. AutocompleteMenu.Items 中键入菜单项的文本。

  3. 设置 TextBoxAutocompleteMenu 属性。

  4. 就这样,各位!

高级用法

  1. AutocompleteMenu 组件放置在您的窗体上。
  2. 创建一个项目列表,并使用 SetAutocompleteItems()AddItem() 方法将其添加到菜单中。例如
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);
}

此外,您还可以添加自己的项,这些项派生自 AutocompleteItem。例如

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;
    }
}

有关更多详细信息,请参阅演示应用程序的 AdvancedSample 示例。

快捷方式

您可以使用以下快捷键

  • Ctrl+Space - 强制打开 AutocompleteMenu
  • Up, Down, PgUp, PgDown - 在菜单中导航
  • Enter, Tab, DblClick on the item - 将选定的项插入文本(仅当 AllowTabKey 为 true 时,Tab 键才有效)。
  • Esc - 关闭菜单

请注意,即使焦点在 textbox 中,这些键也会起作用。

单击某项时,该项的工具提示会显示出来。

自定义 ListView

您可以使用自定义控件来显示 AutocompleteMenu(例如 ListViewListBoxDataGridViewTreeView 等)。为此,请创建自己的控件(派生自 Control)并实现 IAutocompleteListView 接口。有关更多详细信息,请参阅 CustomListViewSample

动态上下文菜单

通常需要菜单显示一个动态变化的项集,而不是固定的项集,具体取决于文本。此任务可以解决。

请注意,菜单的 SetAutocompleteItems() 方法接受 IEnumerable 作为要显示的项的集合。

因此,您不是在程序开始时生成一个项列表,而是在菜单调用枚举器时动态生成它。

以下代码演示了这一概念

    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);
        }
    }

有关完整实现的示例,请参阅 DynamicMenuSample

兼容性

Autocomplete 菜单与 TextBoxRichTextBoxMaskedTextBox、FastColoredTextBox[^] 和其他派生自 TextBoxBase 的控件兼容。

此外,Autocomplete Menu 还兼容支持以下属性和方法的任何控件

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

即使您的控件不支持这些方法,您也可以创建自己的包装器。为此,您需要创建自己的包装器类并在此处实现 ITextBoxWrapper 接口。

以下描述了 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;
    }

因此,在创建包装器后,您可以简单地将 AutocompleteMenu 附加到您的控件。大致如下

    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
	.....
    }

示例

演示应用程序包含几个示例

  • SimplestSample - 展示了如何以最简单的方式使用该控件。
  • CustomItemSample - 展示了如何创建派生自 AutocompleteItem 的自定义类。
  • AdvancedSample - 展示了如何创建具有关键字、代码片段、方法建议、文本校正器等的自定义自动完成菜单。
  • ExtraLargeSample - 演示了该组件处理海量菜单项(一百万个)的性能。
  • ComboboxSample - 展示了如何创建类似 Combobox 的控件,但具有非常大的下拉列表并支持按子字符串搜索。
  • MulticolumnSample - 展示了如何创建多列自动完成菜单。

  • CustomListViewSample - 展示了如何在自动完成菜单中托管自定义 ListView

  • DynamicMenuSample - 此示例展示了如何创建动态的、上下文敏感的自动完成菜单。
  • DataGridViewSample - 展示了如何将 AutocompleteMenu 附加到 DataGridView

历史

  • 2012 年 4 月 13 日 - 首次发布
  • 2012 年 4 月 21 日 - 对控件进行了重构。增加了对 FastColoredTextBox[^] 和其他控件的支持。
  • 2012 年 5 月 9 日 - 对控件进行了重构。添加了一些示例。
  • 2014 年 12 月 3 日 - 添加了 Colors 属性。
  • 2015 年 2 月 8 日 - 修复了一些小错误。
  • 2015 年 3 月 19 日 - 修复了一些小错误。
© . All rights reserved.