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 设置为“None”,同时更改字符串,之后将其设置回“SuggestAppend”。 - 钩取 TextUpdate 或 KeyPress 事件,而不是 TextChanged。 - 每次用新的 AutoCompleteStringCollection 替换现有的 AutoCompleteCustomSource。
没有这些方法有所帮助,即使是多种组合。Spence建议我尝试覆盖
ComboBox
函数,以获取用于自动完成的字符串列表。使用反射器,我在ComboBox
类中找到了几个看起来很有前途的方法-GetStringsForAutoComplete()
和SetAutoComplete()
,但它们都是私有的,所以我无法从派生类中访问它们。我无法继续下去。我试着用
TextBox
替换ComboBox
,因为自动完成接口相同,我发现行为略有不同。使用TextBox
,它似乎效果更好,自动完成的附加部分可以正常工作,但建议部分不行-建议框短暂地闪现然后立即消失。所以我想:“好吧,我将放弃建议功能,只使用追加”,但是当我将
AutoCompleteMode
设置为追加时,我会收到访问冲突异常。建议也会发生同样的事情-唯一不会引发异常的模式是SuggestAppend
,即使建议部分也无法正确地工作。我认为使用C#托管代码时不可能出现访问冲突异常。Avram建议我使用"lock"来解决这个问题,但我不知道该锁定什么——唯一有SyncRoot成员的是
AutoCompleteStringCollection
,但锁定它并不能防止访问违规异常。我也尝试过锁定ComboBox
或TextBox
,但也没有帮助。据我所知,锁只能防止其他锁,因此如果底层代码没有使用锁,则我使用锁也不会有任何影响。总之,我目前无法使用具有动态自动完成功能的
TextBox
或ComboBox
。是否有人了解如何实现这一点?更新:
我还没有解决这个问题,但我发现了更多信息。也许这些信息会激发其他人想出一个解决方案。
我尝试用
TextBox
替换ComboBox
,因为自动完成接口相同,但我发现行为略有不同。使用TextBox
时,它似乎工作得更好,因为自动完成的追加部分正常工作,但建议部分不起作用——建议框短暂地闪烁一下,然后立即消失。
因此我想 “好吧,我可以放弃建议功能只使用“Append”,但是当我将 AutoCompleteMode
设为 Append 时,会出现访问冲突异常。对于Suggest也是一样的情况——唯一不会抛出异常的模式是 SuggestAppend
,即使这样 Suggest 部分的行为也不正确。
我曾认为,在使用 C# 托管代码时不可能出现访问冲突异常,但无论如何,问题在于我目前无法使用任何类型的自动完成功能与 TextBox
或 ComboBox
。有没有人知道我怎样才能实现它呢?
更新2:
在尝试了其他各种方法,例如在工作线程中更改自动完成,使用 BeginInvoke()
模拟 PostMessage() 类型的行为后,最终我放弃了,并使用列表框实现了自己的自动完成下拉框。它比内置的更加响应,并且我花费的时间比试图使内置的正常工作所用的时间还要短,因此,对于任何想要此行为的其他人而言,教训就是:你可能最好自己实现它。