我的wpf应用程序中有一个texbox控件,我希望在用户输入时获得一个自动完成列表框。换句话说,我有类似google的搜索框:
我已经设法以两种方式做到这一点,我想知道哪一种更有效。
当用户在每次texbox更改时键入文本框时,我通过查询数据库来更新列表框。因此我有类似的东西:
void textBox1_KeyUp(object sender, KeyEventArgs e)
{
// new text
var content = ((TextBox)sender).Text;
// I am selecting the posible items using ado.net
var posibleItems= PdvEntities.Entities.TableFoos.Where(TableFoo=> TableFoo.Description.Contains(content)).Select(c=>c);
listbox1.ItemsSource = posibleItems;
}
请注意,通过这种方法,每次keyup事件在该文本框中触发时,我都会查询数据库。
不是每次启动keyup事件时都查询数据库,而是执行以下操作:
// select all items and store that as a global variable
IQueryable allItems = PdvEntities.Entities.TableFoos.Select(a => a);
void textBox1_KeyUp(object sender, KeyEventArgs e)
{
// new text
var content = ((TextBox)sender).Text;
// I don't have the code but I will then filter variable
// allItems based if their description contains 'content'
// pseudo code
newFileter <- filter of allItems that contain content
listbox1.ItemsSource = newFileter;
}
不是说在这种情况下我只查询一次数据库,每当我需要将项目添加到列表框时,我将查询IQueryable变量而不是数据库。我担心如果数据库很大,这种技术会占用大量内存。
另外我忘了提到数据库可能不是本地的。现在我在本地连接到数据库,但此应用程序可能与远程数据库连接一起运行。哪种方法更有效?
答案 0 :(得分:3)
两个版本之间不会有任何显着差异。那是因为以下代码没有按照您的想法执行:
// select all items and store that as a global variable
IQueryable allItems = PdvEntities.Entities.TableFoos.Select(a => a);
它不会“存储”字段中的所有项目,甚至根本不会进入数据库。它只是一个查询,如果你迭代它可以检索所有项目。
另一方面,如果你做了类似
的事情Foo[] allItems = PdvEntities.Entities.TableFoos.ToArray();
实际上会将所有项目检索到内存中。但如果我们不了解您的数据库和执行环境的所有内容,就无法知道哪一个会更有效。
答案 1 :(得分:1)
如果您的PdvEntities
类是EntityFramework上下文,则以下是Linq-to-Entities查询,该查询将针对您的数据库生成T-SQL并仅获取已过滤的项目。
var posibleItems= PdvEntities.Entities.TableFoos
.Where(TableFoo=> TableFoo.Description.Contains(content)).Select(c=>c);
不确定我理解您的其他解决方案。正如@svik提到的那样您可以使用ToArray()
和ToList()
来获取内存中的所有项目,但这根本不是完整的。
看起来您需要限制对数据库的调用,因此使用类型时,每隔n
秒发送一次带过滤器的查询。
看看system.reactive。它将允许您以一种很好的方式限制您的键盘事件。
我在这里写了一篇文章:
http://www.gideondsouza.com/blog/implementing-simple-instant-search-with-rx-reactive-extensions(这只是限制搜索)
然后另一个谈论linq-to-entities来限制数据库搜索:
http://www.gideondsouza.com/blog/abstracting-reactive-extensions-for-sql-server-compact-and-implementing-an-instant-search
基于我在文章中写的东西你可以做这样的事情:
你需要一个小帮手
public class ObservableHelper<T>
where T : class //or EntityObject
{
public ObservableHelper()
{
_dat = new PdvEntities();
}
PdvEntities _dat;
public IObservable<IList<T>> GetAllAsObservables
(Func<PdvEntities, IQueryable<T>> funcquery)
{
var getall = Observable.ToAsync<PdvEntities, IQueryable<T>>(funcquery);
return getall(_dat).Select(x => x.ToList());
}
}
表单中的然后:
public Form1()
{
InitializeComponent();
//your playing with IQueryable<TableFoos>
_repo = new ObservableHelper<TableFoos>()
Observable.FromEventPattern(h => textBox1.KeyUp += h,
h => textBox1.KeyUp -= h)//tell Rx about our event
.Throttle(TimeSpan.FromMilliseconds(500), cs)///throttle
.ObserveOn(Scheduler.Dispatcher);//so we have no cross threading issues
.Do(a => SearchList(textBox1.Text))//do this method
.Subscribe();
}
IObservableHelper<TableFoos, PdvEntities> _repo;
void SearchList(string query)
{//AS MANY keystrokes are there, this function will be called only
// once every 500 milliseconds..
listBox1.Items.Clear();
listBox1.BeginUpdate();
var getfn = _repo.GetAllAsObservables
(d => d.TableFoos.Where(c => c.TableFoos.Contains(query)));
getfn.ObserveOn(this).Subscribe(resultList => //is an IList<TableFoos>
{
foreach (var item in resultList)
{
listBox1.Items.Add(...
}
listBox1.EndUpdate();
});
}