搜索列表中的任何位置,而不仅仅是第一个字母

时间:2015-12-26 10:48:08

标签: c# combobox autocomplete

我想要做的是搜索一个ComboBox,一个单词或一个单词的一部分,如下所示:

例如,我在组合框中有这些条目:

abc
Abc
Dabc
adbdcd

当我搜索“abc”时,它应该向我展示列表中的每一个,除了“

adbdcd"

我从mysql数据库中填充我的组合框,所以我的项目位于“Collection”。

我启用了自动完成功能(模式:SuggestAppend,来源:ListItems

这是我现在正在使用的代码:

private void comboBox1_KeyPress(object sender,KeyPressEventArgs e)         {             comboKey​​Pressed();         }

    private void comboBox1_TextChanged(object sender, EventArgs e)
    {
        if (comboBox1.Text.Length == 0) comboKeyPressed();
    }

    private void comboKeyPressed()
    {
        comboBox1.DroppedDown = true;

        object[] originalList = (object[])comboBox1.Tag;
        if (originalList == null)
        {
            // backup original list
            originalList = new object[comboBox1.Items.Count];
            comboBox1.Items.CopyTo(originalList, 0);
            comboBox1.Tag = originalList;
        }

        // prepare list of matching items
        string s = comboBox1.Text.ToLower();
        IEnumerable<object> newList = originalList;
        if (s.Length > 0)
        {
            newList = originalList.Where(item => item.ToString().ToLower().Contains(s));
        }

        // clear list (loop through it, otherwise the cursor would move to the beginning of the textbox...)
        while (comboBox1.Items.Count > 0)
        {
            comboBox1.Items.RemoveAt(0);
        }

        // re-set list
        comboBox1.Items.AddRange(newList.ToArray());
    }

此代码的问题是,如果我在示例列表中搜索“abc”,“adbdcd”也会显示。当我在组合框中点击退格键时,这段代码会随机崩溃我的程序。

3 个答案:

答案 0 :(得分:0)

这是崩溃的根本原因:

    while (comboBox1.Items.Count > 0)
    {
        // this is raising exception if you try to remove the last item
        // Check the doc of RemoveAt
        comboBox1.Items.RemoveAt(0);
    }

使用它代替:

comboBox1.Items.Clear();

然而,你想要实现的目标仍然不清楚。 如果combox的文本为空,那么除了清除并重新添加相同的项目到组合框之外,什么都不会发生。

我的理解是,您在尝试启用时会尝试复制完成行为。它也可以引发异常( AccessViolationException ),因为您尝试在框架尝试执行相同操作时修改Items集合。

如果您对默认的自动完成行为不满意,请将其禁用并尝试在comboKeyPressed方法中完全实现。 这意味着每当文本被修改时调用它。

修改代码以使其正常工作 通过禁用自动完成功能):

    private void comboBox1_TextChanged(object sender, EventArgs e)
    {
        comboKeyPressed();
    }

    private void comboKeyPressed()
    {
        if (comboBox1.Text == lastFilter)
        {
            return;
        }

        object[] originalList = (object[]) comboBox1.Tag;
        if (originalList == null)
        {
            // backup original list
            originalList = new object[comboBox1.Items.Count];
            comboBox1.Items.CopyTo(originalList, 0);
            comboBox1.Tag = originalList;
        }

        // prepare list of matching items
        string s = comboBox1.Text.ToLower();
        IEnumerable<object> newList = originalList;
        if (s.Length > 0)
        {
            newList = originalList.Where(item => item.ToString().ToLower().Contains(s));
        }            
        // clear list (loop through it, otherwise the cursor would move to the beginning of the textbox...)
        comboBox1.Items.Clear();
        // re-set list
        comboBox1.Items.AddRange(newList.ToArray());

        comboBox1.Select(Text.Length -1, 0);

        lastFilter = comboBox1.Text;
        comboBox1.DroppedDown = true;
    }

答案 1 :(得分:0)

所以,你想要全文搜索。

您的数据来自哪里?它是什么类型的数据?有什么边缘案例?

对于数据库,我喜欢使用 Sphinx 进行全文索引。

对于内存数据,高效的全文搜索算法包括后缀数组,后缀树和Patricia尝试。实施它们可能是一项有趣(且耗时)的挑战。或者您可以在线找到合适的实施方案。您可以找到这些算法的准系统实现,以及更全面的全文搜索实现,例如 Lucene

为了让您了解它们的工作原理,想象一下您存储的每个单词的每个可能后缀,例如: needle

  • eedle
  • edle
  • DLE
  • 文件
  • ë

将所有这些后缀放入有序数据结构中,例如排序数组或列表(对于静态数据)或B树或SortedDictionary(如果定期添加数据)。插入needle后,它将包含:

  • DLE
  • ë
  • edle
  • eedle
  • 文件

现在我们可以使用二分搜索或更好的方式搜索单词的任何部分(例如edl),看看我们是否有点击。

要提取更多信息,而不仅仅是我们是否有点击,我们可以将数据添加到,例如,SortedDictionary的。 (我们将后缀用作。)有趣的数据可能是整个单词,也可能是遇到单词的原始文本和位置。

答案 2 :(得分:0)

如果要搜索的条目数总是很低 - 可能不会超过几百 - 那么一个简单的实现就足够了。

// Select all words that contain our query string
var matchingWords = wordList.Where(word => word.Contains(query));

这是天真的线性实现,对于大数据来说会变得很慢。但是对于小数据来说,它非常简单。只需将新子集提供给组合框即可。

您可能希望使用其可选的第二个参数为Contains()调用添加不区分大小写。