c# - 如何动态更改 C# 组合框或文本框中的自动完成条目?

标签 c# winforms autocomplete combobox textbox

我在 C# 中有一个组合框,我想对它使用自动完成建议,但是我希望能够在用户键入时更改自动完成条目,因为可能的有效条目太多而无法填充 AutoCompleteStringCollection在启动时。
举个例子,假设我让用户输入一个名字。我有一个可能的名字列表(“Joe”、“John”)和一个姓氏列表(“Bloggs”、“Smith”),但是如果我每个都有一千个,那么这将是一百万个可能的字符串 -太多无法放入自动完成条目。因此,最初我只想将名字作为建议 ("Joe", "John") ,然后一旦用户输入名字 ("Joe"),我想删除现有的自动完成条目并替换他们使用一个新的集合,由选定的名字和可能的姓氏组成(“Joe Bloggs”、“Joe Smith”)。为了做到这一点,我尝试了以下代码:

void InitializeComboBox()
{
    ComboName.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
    ComboName.AutoCompleteSource = AutoCompleteSource.CustomSource;
    ComboName.AutoCompleteCustomSource = new AutoCompleteStringCollection();
    ComboName.TextChanged += new EventHandler( ComboName_TextChanged );
}

void ComboName_TextChanged( object sender, EventArgs e )
{
    string text = this.ComboName.Text;
    string[] suggestions = GetNameSuggestions( text );

    this.ComboQuery.AutoCompleteCustomSource.Clear();
    this.ComboQuery.AutoCompleteCustomSource.AddRange( suggestions );
}
但是,这不能正常工作。似乎调用 Clear() 会导致自动完成机制“关闭”,直到下一个字符出现在组合框中,但是当然当下一个字符出现时,上面的代码再次调用 Clear(),因此用户永远不会实际上看到了自动完成功能。它还会导致组合框的整个内容被选中,因此在每次按键之间您必须取消选择现有文本,这使其无法使用。如果我删除对 Clear() 的调用,则自动完成工作,但似乎是 AddRange()调用无效,因为我添加的新建议不会出现在自动完成下拉列表中。
我一直在寻找解决方案,并看到了各种建议,但我无法让它们中的任何一个工作 - 自动完成功能似乎被禁用,或者没有出现新字符串。这是我尝试过的事情的列表:
  • 调用 BeginUpdate()在更改字符串和 EndUpdate() 之前之后。
  • 调用 Remove()在所有现有字符串上,而不是 Clear()。
  • 在更新字符串时清除组合框中的文本,然后将其添加回来。
  • 设置 AutoCompleteMode更改字符串时设置为“无”,然后将其设置回“SuggestAppend”。
  • Hook TextUpdateKeyPress事件而不是 TextChanged .
  • 替换现有 AutoCompleteCustomSource带新 AutoCompleteStringCollection每一次。

  • 这些都没有帮助,即使在各种组合中也是如此。 Spence建议我尝试覆盖 ComboBox获取要在自动完成中使用的字符串列表的函数。使用反射器,我在 ComboBox 中找到了几种方法看起来很有前途的类(class) - GetStringsForAutoComplete()SetAutoComplete() ,但它们都是私有(private)的,因此我无法从派生类访问它们。我不能再这样下去了。
    我尝试更换 ComboBoxTextBox ,因为自动完成界面是一样的,我发现行为略有不同。与 TextBox它似乎工作得更好,因为自动完成的附加部分工作正常,但建议部分没有 - 建议框短暂闪烁,然后立即消失。
    所以我想“好吧,我会在没有 Suggest 功能的情况下生活,而只是使用 Append”,但是当我设置 AutoCompleteMode 时追加,我得到一个访问冲突异常。同样的事情发生在 Suggest - 唯一不抛出异常的模式是 SuggestAppend ,即使 Suggest 部分的行为不正确。
    我认为在使用 C# 托管代码时应该不可能获得访问冲突异常。 Avram建议我使用“锁定”来解决这个问题,但我不知道我应该锁定什么 - 唯一具有 SyncRoot 成员的是 AutoCompleteStringCollection ,并锁定不会阻止访问冲突异常。我也尝试锁定 ComboBoxTextBox ,但这也无济于事。据我了解,锁只能防止其他锁,所以如果底层代码没有使用锁,那么我使用它不会有任何区别。
    所有这一切的结果是我目前无法使用 TextBoxComboBox具有动态自动完成功能。有没有人对我如何实现这一目标有任何见解?
    更新:
    我仍然没有得到这个工作,但我发现了更多。也许其中一些会激励其他人提出解决方案。
    我尝试更换 ComboBoxTextBox ,因为自动完成界面是一样的,我发现行为略有不同。与 TextBox它似乎工作得更好,因为自动完成的附加部分工作正常,但建议部分没有 - 建议框短暂闪烁,然后立即消失。
    所以我想“好吧,我会在没有 Suggest 功能的情况下生活,而只是使用 Append”,但是当我设置 AutoCompleteMode 时追加,我得到一个访问冲突异常。同样的事情发生在 Suggest - 唯一不抛出异常的模式是 SuggestAppend ,即使 Suggest 部分的行为不正确。
    我认为在使用 C# 托管代码时应该不可能获得访问冲突异常,但无论如何,结果是我目前无法使用 TextBoxComboBox任何类型的动态自动完成。有没有人对我如何实现这一目标有任何见解?
    更新 2:
    在尝试了各种其他事情之后,例如更改工作线程中的自动完成功能,并使用 BeginInvoke()为了模拟 PostMessage() 类型的行为,我终于放弃了,只是使用列表框实现了我自己的自动完成下拉列表。它比内置的响应更快,而且我花在这方面的时间比尝试让内置的工作要少得多,所以对于想要这种行为的其他人来说,教训是 - 你可能会过得更好自己实现。

    最佳答案

    我遇到了同样的问题,并找到了一个非常简单的解决方法。和这里的其他人一样,我找不到任何方法来控制组件的行为,所以我不得不接受它。

    自然的行为是:您不能在用户每次在文本框中键入内容时动态填充列表。您必须填充一次,然后 AutoComplete 机制取得控制权。结论是:您应该使用数据库中的每个可能条目填充 AutoCompleteCustomSource 以使其按我们想要的方式工作。

    当然,如果您有数百万条记录来填充列表,这是不可行的。数据传输中的性能问题和自动完成机制本身不允许您这样做。

    我找到的折衷解决方案是:每次文本长度恰好达到 N 个字符(在我的情况下为 3 个)时,动态填充 AutoCompleteCustomSource。这是有效的,因为复杂性大大降低。从数据库中提取的与这 3 个初始字符匹配的记录数量足够小,可以避免任何性能问题。

    主要缺点是:在用户键入第 N 个字符之前,他们不会看到自动完成列表。但在输入 3 个字符之前,用户似乎并不真正期望一个有意义的自动完成列表。

    希望这可以帮助。

    关于c# - 如何动态更改 C# 组合框或文本框中的自动完成条目?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/515561/

    相关文章:

    C#、MVC 确认删除对话框

    c# - 如何通过 linq 查询对组中的元素进行排序,然后选择第一个?

    c# - 将文本框绑定(bind)到列表框 SelectedItem

    winforms - 手动向 DataGridView 添加新行不会立即更新绑定(bind)的 DataTable

    java - 在 Java Web 应用程序中使用静态方法和变量

    c# - 预启动任务构建以退出代码 1 终止

    c# - 用于检查电视节目的正则表达式

    c# - 带有大小参数的不成比例的气泡图

    search - Magento - 自动完成建议搜索不起作用

    symfony - 将 Javascript 标签库与 Sonata Admin Bundle 集成的 bundle