大家好!我尽我所能搜索,并没有找到我正在寻找的帮助。
执行查询时,AutoCompleteTextbox FREEZES和“吃”字符
模仿Google即搜即得功能
首先要做的事:C#,WPF,.NET 4.0
好的,现在已经开始了,我正在尝试找到实现动态自动完成文本框的最佳方法,该文本框在每个字母输入后查询数据库以查找结果。
触发AutoCompleteTextBox的TextChanged事件时会执行以下代码:
public void Execute(object sender, object parameter)
{
//removed some unnecessary code for the sake of being concise
var autoCompleteBox = sender as AutoCompleteTextBox;
var e = parameter as SearchTextEventArgs;
var result = SearchUnderlyings(e.SearchText);
autoCompleteBox.ItemsSource = result;
}
现在,让我们说SearchUnderlyings(e.SearchText)
平均需要600-1100毫秒 - 在此期间,文本框被冻结并且“吃掉”按下的任何键。这是我一直遇到的烦人问题。出于某种原因,SearchUnderlyings(e.SearchText)
中的LINQ正在GUI线程中运行。我尝试将此委托给后台线程,但结果仍然相同。
理想情况下,我希望文本框能够像Google Instant一样工作 - 但我不希望在服务器/查询返回结果之前“杀死”线程。
任何人都有经验或可以提供一些指导,这样我可以在不冻结GUI或查杀服务器的情况下查询?
谢谢你们!
答案 0 :(得分:4)
这一行:
var result = SearchUnderlyings(e.SearchText);
同步运行,锁定UI线程。解决这个问题的方法是切换到异步模式,然后启动查询,然后在完成时执行某些操作。
本文非常精彩地展示了它,并展示了一些解决方案 - http://www.codeproject.com/KB/cs/AsyncMethodInvocation.aspx
答案 1 :(得分:2)
可能会杀死你的是一遍又一遍地设置绑定源(这就是为什么在后台线程上运行查询没有什么区别)。
您可以将算法视为一个整体。根据您的数据,您可以等到用户输入前三个字符,然后对数据库执行一次大型查询。绑定项目源一次。之后键入的每个字符只对已经缓存在客户端上的数据执行过滤。这样你就不会一遍又一遍地攻击数据库(这将是非常昂贵的)。
或者考虑从数据库中带回三个左右的结果,以保持服务序列化时间。
答案 2 :(得分:1)
所以,我们有点快速入侵了。通过调用SearchUnderlyings(e.SearchText)异步,我的GUI线程不再被阻止,文本框不再“吃掉”按键。通过添加lastQueryTag == _lastQuery
检查,我们尝试确保一些线程安全,只允许最新的查询来设置ItemsSource。
也许不是最理想或最优雅的解决方案。我仍然愿意接受进一步的批评和建议。谢谢!
private long _lastQuery = DateTime.Now.Ticks;
public void Execute(object sender, object parameter)
{
var autoCompleteBox = sender as AutoCompleteTextBox;
var e = parameter as SearchTextEventArgs;
// removed unecessary code for clarity
long lastQueryTag = _lastQuery = DateTime.Now.Ticks;
Task.Factory.StartNew(() =>
{
var result = SearchUnderlyings(e.SearchText);
System.Windows.Application.Current.Dispatch(() =>
{
if (lastQueryTag == _lastQuery)
autoCompleteBox.ItemsSource = result;
});
});
}