【发布时间】:2010-10-05 15:49:29
【问题描述】:
我在 C# 中有一个组合框,我想使用自动完成建议,但是我希望能够在用户键入时更改自动完成条目,因为可能的有效条目太多而无法填充 @ 987654323@在启动时。
举个例子,假设我让用户输入一个名字。我有一个可能的名字列表(“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设置为“None”,然后将其设置回“SuggestAppend”。 - 挂钩
TextUpdate或KeyPress事件而不是TextChanged。 - 每次都将现有的
AutoCompleteCustomSource替换为新的AutoCompleteStringCollection。
这些都没有帮助,即使是各种组合。 Spence 建议我尝试覆盖 ComboBox 函数,该函数获取要在自动完成中使用的字符串列表。使用反射器,我在ComboBox 类中发现了一些看起来很有希望的方法——GetStringsForAutoComplete() 和SetAutoComplete(),但它们都是私有的,因此我无法从派生类访问它们。我受不了了。
我尝试将ComboBox 替换为TextBox,因为自动完成界面相同,但我发现行为略有不同。使用 TextBox 似乎效果更好,因为自动完成的 Append 部分可以正常工作,但 Suggest 部分不能 - 建议框短暂地闪烁,然后立即消失。
所以我想“好吧,我可以不用 Suggest 功能而只使用 Append”,但是当我将 AutoCompleteMode 设置为 Append 时,我得到了访问冲突异常。 Suggest 也会发生同样的事情 - 唯一不会引发异常的模式是 SuggestAppend,即使 Suggest 部分行为不正确。
我认为在使用 C# 托管代码时应该不可能出现访问冲突异常。 Avram 建议我使用“锁定”来解决此问题,但我不知道我应该锁定什么 - 唯一具有 SyncRoot 成员的是 AutoCompleteStringCollection,并且锁定不会阻止访问冲突异常。我还尝试锁定ComboBox 或TextBox,但这也无济于事。据我了解,lock 只会阻止其他锁,所以如果底层代码没有使用 lock,那么我使用它不会有任何区别。
所有这一切的结果是,我目前无法使用具有动态自动完成功能的 TextBox 或 ComboBox。有人对我如何实现这一点有任何见解吗?
更新:
我还没有得到这个工作,但我发现了更多。也许其中一些会激发其他人提出解决方案。
我尝试将ComboBox 替换为TextBox,因为自动完成界面相同,但我发现行为略有不同。使用 TextBox 似乎效果更好,因为自动完成的 Append 部分可以正常工作,但 Suggest 部分不能 - 建议框短暂地闪烁,然后立即消失。
所以我想“好吧,我可以不用 Suggest 功能而只使用 Append”,但是当我将 AutoCompleteMode 设置为 Append 时,我得到了访问冲突异常。 Suggest 也会发生同样的事情 - 唯一不会引发异常的模式是 SuggestAppend,即使 Suggest 部分行为不正确。
我认为在使用 C# 托管代码时应该不可能出现访问冲突异常,但无论如何,结果是我目前无法将 TextBox 或 ComboBox 用于任何动态自动完成。有人对我如何实现这一点有任何见解吗?
更新 2:
在尝试了各种其他事情(例如更改工作线程中的自动完成功能,并使用BeginInvoke() 模拟 PostMessage() 类型的行为之后,我终于放弃了,只是使用列表框实现了我自己的自动完成下拉菜单。它比内置的响应速度更快,而且我花在这方面的时间比我试图让内置的工作的时间少,所以任何想要这种行为的人的教训是 - 你可能会更好自己实现。
【问题讨论】:
标签: c# winforms autocomplete combobox textbox