带有子字符串搜索的自动完成文本框,类似于 SQL Like 或 Contains






4.66/5 (23投票s)
具有自动完成功能的文本框,

引言
我一直在寻找具有子字符串匹配功能的TextBox
自动完成功能。我找到的解决方案有点笨拙,所以这是我相当简单但稳定的解决方案。
背景
这是我的第一篇文章,所以不要期望它是完美的。我认为代码注释有点过头了,但这使源代码能够自我解释。
嗯,与其他方法有一些不同。首先,我们使用Panel
而不是Form
来显示建议列表。其次,我们使用IndexOf
而不是Linq
来查找匹配项。第三,我们只使用纯粹安全的 .NET 代码,没有 Win32 调用,也没有草率的线程处理,例如sleep()
或其他东西。
幕后
在主窗体的Load
事件中,我们读取一个名为“en-EN.dic”的文本文件,这是一个包含超过 50,000 个条目的字典。 它将被存储在组件的AutoCompleteList
属性中,该属性是一个List<string>
。
虽然AutoCompleteList
用作“数据库”并且保持不变,但CurrentAutoCompleteList
属性包含适当候选者的子集,这些候选者将显示为下面的ListBox
中的建议。
主要工作在一个名为ShowSuggests()
的方法中完成,该方法调用一个时间关键方法UpdateCurrentAutoCompleteList()
,然后该方法调用第二个时间关键方法UpdateListBoxItems()
。我提到这一点是因为要显示的元素的内部列表和最终添加到图像框的列表都是耗时的操作,可能会导致滞后的响应。那么,我们为什么为我们的数据使用两个列表呢?好吧,这不是最后要说的话,但我发现DataSource
/DataContext
比在子字符串查询中将单个项目添加到listbox
中更快(参见if ((Str.IndexOf(this.Text) > -1))
)。
Using the Code
该组件像普通的TextBox
一样使用,只是它有一些可以设置的“特殊”属性(CaseSensitive
、MinTypedCharacters
和AutoCompleteList
)。可以在窗体的Load
事件中找到用法的示例。简而言之:将其拖到Form
中,并将短语的List<string>
分配给AutoCompleteList
属性。
需要提到的一些事情
我已经做了一些性能测量和替代实现,因此您可以在ArrayList
或List<string>
基础上进行切换。我选择了第二个,因为它是一个 通用类型。但是,我发现ArrayList
在大型数据(大约 10MB 大小的字典)上表现更好。也许您想进一步研究,请参阅注释。
您会发现两个离题,称为 excursion(英语不好),就像源代码中这样
#region Digression: Performance measuring of Linq queries
// This is a simple example of speedmeasurement for Linq queries
/*
CurrentAutoCompleteList.Clear();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
// using Linq query seems to be slower (twice as slow)
var query =
from expression in this.AutoCompleteList
where expression.ToLower().Contains(this.Text.ToLower())
select expression;
foreach (string searchTerm in query)
{
CurrentAutoCompleteList.Add(searchTerm);
}
stopWatch.Stop();
// method (see below) for printing the performance values to console
PrintStopwatch(stopWatch, "Linq - Contains");
*/
#endregion Digression: Performance measuring of Linq queries
这些区域内的代码没有注释,旨在比较上面所示情况下的替代实现,以测量替代 Linq 查询的性能。
另一个离题是关于切换到使用AddRange
来填充建议列表的方法。在示例代码中,使用的默认方法是手动更新BindingContext
。如果您遇到问题,请随时选择另一种方法。
以下是如何手动更新ListBox
的BindingContext
// bind the data in the constructor
listBox.DataSource = CurrentAutoCompleteList;
// later on, use the CurrencyManager to update the BindingContext manually
((CurrencyManager)listBox.BindingContext[CurrentAutoCompleteList]).Refresh();
// note that Panel and ListBox have to be added to the ParentForm for this to work!!!
剩下的就是正确的计时,以及知道何时显示组件以及如何处理一个组件中两个组件的键和鼠标事件。 因此,我们处理PageUp
和PageDown
键的KeyDown
事件、MouseClick
和MouseDoubleClick
事件。 我们确保组件适合ParentForm
,避免闪烁和重叠等等。
祝您编码愉快!