当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何在C#组合框或文本框中动态更改自动完成条目?》经验,为你挑选了1个好方法。

我在C#中有一个组合框,我想用它来使用自动完成建议,但是我希望能够在用户输入时更改自动完成条目,因为可能的有效条目太多而无法AutoCompleteStringCollection在启动时填充.

例如,假设我让用户输入名称.我有一个可能的名字列表("乔","约翰")和一个姓氏列表("博客","史密斯"),但如果我有一千个,那么这将是一百万个可能的字符串 - 太多,无法输入自动完成条目.所以最初我想只有名字作为建议("乔","约翰"),然后一旦用户键入了第一个名字("乔"),我想删除现有的自动完成条目并替换他们使用一个新的集合,包括所选的名字,然后是可能的姓氏("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".

挂钩TextUpdateKeyPress事件而不是TextChanged.

每次都AutoCompleteCustomSource用新的替换现有的AutoCompleteStringCollection.

即使在各种组合中,这些都没有帮助. Spence建议我尝试覆盖ComboBox获取要在auto complete中使用的字符串列表的函数.使用反射我发现一对夫妇的方法ComboBox类看好- GetStringsForAutoComplete()SetAutoComplete(),但它们都是私人,所以我无法从派生类访问它们.我不能再接受了.

我尝试用ComboBoxa 代替TextBox,因为自动完成界面是一样的,我发现行为略有不同.随着TextBox它似乎工作得更好,因为自动完成的附加部分正常工作,但建议部分没有 - 建议框暂时闪烁生命,但然后立即消失.

所以我想"好吧,我将没有Suggest功能,只使用Append",但是当我设置AutoCompleteMode为Append时,我得到了一个访问冲突异常.Suggest SuggestAppend也会发生同样的事情 - 唯一不会抛出异常的模式是,即使Suggest部分没有正常运行.

我认为在使用C#托管代码时,应该无法获得访问冲突异常. Avram建议我使用"lock"来修复此问题,但我不知道应该锁定什么 - 唯一具有SyncRoot成员的是AutoCompleteStringCollection,并且锁定不会阻止访问冲突异常.我也试过锁定ComboBoxTextBox,但这也没有帮助.据我了解,锁只能防止其他锁,所以如果底层代码没有使用锁,那么我使用它将没有任何区别.

所有这一切的结果是我目前无法使用动态自动完成TextBoxComboBox动态自动完成.有没有人对我如何实现这一目标有任何见解?

更新:

我还没有这个工作,但我发现了更多.也许其中一些会激励其他人提出解决方案.

我尝试用ComboBoxa 代替TextBox,因为自动完成界面是一样的,我发现行为略有不同.随着TextBox它似乎工作得更好,因为自动完成的附加部分正常工作,但建议部分没有 - 建议框暂时闪烁生命,但然后立即消失.

所以我想"好吧,我将没有Suggest功能,只使用Append",但是当我设置AutoCompleteMode为Append时,我得到了一个访问冲突异常.Suggest SuggestAppend也会发生同样的事情 - 唯一不会抛出异常的模式是,即使Suggest部分没有正常运行.

我认为在使用C#托管代码时应该不可能获得访问冲突异常,但无论如何,结果是我目前无法使用a TextBoxComboBox任何类型的动态自动完成.有没有人对我如何实现这一目标有任何见解?

更新2:

在尝试了各种其他事情,比如更改工作线程中的自动完成,以及使用BeginInvoke()模拟PostMessage()类型行为后,我终于放弃了,并使用列表框实现了我自己的自动完成下拉列表.它比内置的响应更快,而且我花在这上面的时间比我试图让内置的工作更少,所以对于任何想要这种行为的人来说,这个教训是 - 你可能会更好自己实现它.



1> 小智..:

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

自然行为是:每次用户键入文本框时,都无法动态填充列表.您必须填充一次,然后AutoComplete机制将获得控制权.结论是:您应该使用数据库中的每个可能条目填充AutoCompleteCustomSource,以使其按预期工作.

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

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

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

希望这可以帮助.

推荐阅读
郑小蒜9299_941611_G
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有