我在 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”。 TextUpdate
或 KeyPress
事件而不是 TextChanged
. AutoCompleteCustomSource
带新 AutoCompleteStringCollection
每一次。 这些都没有帮助,即使在各种组合中也是如此。 Spence建议我尝试覆盖
ComboBox
获取要在自动完成中使用的字符串列表的函数。使用反射器,我在 ComboBox
中找到了几种方法看起来很有前途的类(class) - GetStringsForAutoComplete()
和 SetAutoComplete()
,但它们都是私有(private)的,因此我无法从派生类访问它们。我不能再这样下去了。我尝试更换
ComboBox
与 TextBox
,因为自动完成界面是一样的,我发现行为略有不同。与 TextBox
它似乎工作得更好,因为自动完成的附加部分工作正常,但建议部分没有 - 建议框短暂闪烁,然后立即消失。所以我想“好吧,我会在没有 Suggest 功能的情况下生活,而只是使用 Append”,但是当我设置
AutoCompleteMode
时追加,我得到一个访问冲突异常。同样的事情发生在 Suggest - 唯一不抛出异常的模式是 SuggestAppend
,即使 Suggest 部分的行为不正确。我认为在使用 C# 托管代码时应该不可能获得访问冲突异常。 Avram建议我使用“锁定”来解决这个问题,但我不知道我应该锁定什么 - 唯一具有 SyncRoot 成员的是
AutoCompleteStringCollection
,并锁定不会阻止访问冲突异常。我也尝试锁定 ComboBox
或 TextBox
,但这也无济于事。据我了解,锁只能防止其他锁,所以如果底层代码没有使用锁,那么我使用它不会有任何区别。所有这一切的结果是我目前无法使用
TextBox
或 ComboBox
具有动态自动完成功能。有没有人对我如何实现这一目标有任何见解?更新:
我仍然没有得到这个工作,但我发现了更多。也许其中一些会激励其他人提出解决方案。
我尝试更换
ComboBox
与 TextBox
,因为自动完成界面是一样的,我发现行为略有不同。与 TextBox
它似乎工作得更好,因为自动完成的附加部分工作正常,但建议部分没有 - 建议框短暂闪烁,然后立即消失。所以我想“好吧,我会在没有 Suggest 功能的情况下生活,而只是使用 Append”,但是当我设置
AutoCompleteMode
时追加,我得到一个访问冲突异常。同样的事情发生在 Suggest - 唯一不抛出异常的模式是 SuggestAppend
,即使 Suggest 部分的行为不正确。我认为在使用 C# 托管代码时应该不可能获得访问冲突异常,但无论如何,结果是我目前无法使用
TextBox
或 ComboBox
任何类型的动态自动完成。有没有人对我如何实现这一目标有任何见解?更新 2:
在尝试了各种其他事情之后,例如更改工作线程中的自动完成功能,并使用
BeginInvoke()
为了模拟 PostMessage() 类型的行为,我终于放弃了,只是使用列表框实现了我自己的自动完成下拉列表。它比内置的响应更快,而且我花在这方面的时间比尝试让内置的工作要少得多,所以对于想要这种行为的其他人来说,教训是 - 你可能会过得更好自己实现。
最佳答案
我遇到了同样的问题,并找到了一个非常简单的解决方法。和这里的其他人一样,我找不到任何方法来控制组件的行为,所以我不得不接受它。
自然的行为是:您不能在用户每次在文本框中键入内容时动态填充列表。您必须填充一次,然后 AutoComplete 机制取得控制权。结论是:您应该使用数据库中的每个可能条目填充 AutoCompleteCustomSource 以使其按我们想要的方式工作。
当然,如果您有数百万条记录来填充列表,这是不可行的。数据传输中的性能问题和自动完成机制本身不允许您这样做。
我找到的折衷解决方案是:每次文本长度恰好达到 N 个字符(在我的情况下为 3 个)时,动态填充 AutoCompleteCustomSource。这是有效的,因为复杂性大大降低。从数据库中提取的与这 3 个初始字符匹配的记录数量足够小,可以避免任何性能问题。
主要缺点是:在用户键入第 N 个字符之前,他们不会看到自动完成列表。但在输入 3 个字符之前,用户似乎并不真正期望一个有意义的自动完成列表。
希望这可以帮助。
关于c# - 如何动态更改 C# 组合框或文本框中的自动完成条目?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/515561/