原文:通通WPF随笔(1)——基于lucene.NET让ComboBox拥有强大的下拉联想功能


  我一直很疑惑百度、谷哥搜索框的下拉联想功能是怎么实现的?是不断地查询数据库吗?其实到现在我也不知道,他们是怎么实现这么高效的。后来在博客园无意邂逅了“鹿神”,搜索引擎唉,听起来就很高端。于是研究了一段时间后就产生了这个WPF的下拉联想控件。

名称:

简拼:

全拼:

区号:

邮编:

  这么强大的功能代码一定会复杂吧?不是的哦,亲~代码只有短短几句哦

界面如下:(下拉框后面的数字为查询的延时,可见效率还是很高滴)

XAML:

<cop:CopAutoCompleted url="{Binding Text, ElementName=DirTextBox}" columnNames="{Binding Text, ElementName=UCSearchColTextBox}" 
textName="{Binding Text, ElementName=TextNameTextBox}" maxItems="{Binding Text, ElementName=TextNameTextBox_Copy}">
<cop:CopAutoCompleted.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding City}" />
<TextBlock Text=" (" Foreground="#FF383838"/>
<TextBlock Text="{Binding Spell}" Foreground="#FF383838" />
<TextBlock Text=")" Foreground="#FF383838"/>
</StackPanel>
</DataTemplate>
</cop:CopAutoCompleted.ItemTemplate>
</cop:CopAutoCompleted>

属性介绍:(该控件继承于ComboBox,只是多了下面4个属性)

  url:设置索引所在的文件夹(稍后会介绍如何创建索引)

  columnNames:设置需要检索的列名

  textName:选择下拉项后显示在text里的列名

  maxItems:下拉框最多显示多少项(如果显示内容过多的话会有延时的感觉,经测试延时是由于后台banding的数据集合改变跟新到界面时产生的,不是lucene的效率问题)

  ItemTemplate:玩WPF的都懂的,设置下拉显示数据的布局内容。这样的话就有了很高的可扩展性和灵活性。

 

1.总体思路


  (1)创建lucene索引:在网上找一个全国城市的数据库,用代码提取出来,分别对里面的各列创建索引。

  (2)查询索引:通过lucene的PrefixQuery类构造查询语句,就可以实现前缀查询出整体。

  (3)ComboBox绑定:这里数据源绑定到ObservableCollection<dynamic>集合(自动通知,方便啊),而其中的每一项为根据查询出的每一项结果动态构造的对象。所以用到dynamic运行时解析。

  

2.详细设计


  基本知识我这里就不详细说了,可参看文章最后的参考文献。

1、创建lucene索引

  我在网上找全国城市数据库时找找到的一个比较全面的是Access的,所以这里特地写了一个创建索引的功能:

  (之前比较流行通用数据库访问层,我基于反射自己写了一个通用数据库DBHelper,由于电脑上没有数据库环境,所以只测试了Access和Sqlite)

  其实就是根据查询结果,对需要创建索引的列添加lucene的索引。代码如下:

private void Button_Click_1(object sender, RoutedEventArgs e)
{
//设置索引文件夹
var directory = FSDirectory.GetDirectory(DirTextBox.Text, true); //创建一个索引,采用StandardAnalyzer对句子进行分词
IndexWriter indexWriter = new IndexWriter(directory, new StandardAnalyzer()); var columnName= ColumnNameTextBox.Text.Split(','); //设置数据库连接字符串
if (ComboBox1.Text=="Sqlite")
{
helper=new CopDb.CopDbHelper(CopDb.CopDbHelper.CopDbType.Sqlite,ConnTestBox.Text);
}
if (ComboBox1.Text=="Access")
{
helper = new CopDb.CopDbHelper(CopDb.CopDbHelper.CopDbType.Access, ConnTestBox.Text);
} int timeOut = Environment.TickCount;
var read = helper.ExecuteReader(SQLStrTextBox.Text);
SqlTimeTextBox.Text = (Environment.TickCount - timeOut).ToString();
while (read.Read())
{
//创建文档
Document doc = new Document();
//添加字段
foreach (var item in columnName)
{
doc.Add(new Field(item, read[item].ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));
}
indexWriter.AddDocument(doc);
}
read.Close(); //对索引文件进行优化
indexWriter.Optimize();
indexWriter.Close();
MessageBox.Show("创建索引完成");
}

2、查询索引

  

  就是构造lucene查询query时用PrefixQuery类就行,如下:

 var cols = SearchColTextBox.Text.Split(',');

            BooleanQuery query = new BooleanQuery();

            foreach (var item in cols)
{
query.Add(new PrefixQuery(new Term(item, SearchTextBox.Text)),BooleanClause.Occur.SHOULD);
}
//query.parse:注入查询条件
var hits = search.Search(query);

3、ComboBox绑定数据源

  

  数据源为ObservableCollection<dynamic>类型集合,后台我们只用动态构造出每一个查询对象添加进集合里即可。初始化dynamic对象时还不能用ExpandoObject,虽然ExpandoObject很方便,但是这是一个封闭类,不能继承。ComboBox在选中其中一项显示到文本框里时,其实是执行了选中项数据源的ToString()方法。所以不能重载ExpandoObject的ToString()方法。所以这里自定义了一个轻量级的ExpandoObject类,继承于DynamicObject实现。

代码:

class dyData:DynamicObject
{
public dyData(string colName)
{
this.colName = colName;
}
//ToString时需要输出的属性
public string colName { get; set; }
//用于存储属性名和对应的值
Dictionary<string, object> data = new Dictionary<string, object>();
//绑定时获取对应属性的值
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
return data.TryGetValue(binder.Name,out result);
}
//用于添加属性和对应的值
public void SetValue(string name, object value)
{
data.Add(name, value);
} //重写Tostring方法
public override string ToString()
{
try
{
return data[colName].ToString();
}
catch (Exception ex)
{
MessageBox.Show("找不到列名"+colName,"设置text要显示的项名时出错",MessageBoxButton.OK,MessageBoxImage.Error);
return null;
}
} }

  这样就实现了一个简易的ExpandoObject了。接下来遍历查询结果,通过SetValue动态创建对象的属性,添加进ObservableCollection<dynamic>数据集合,ComboBox直接数据绑定即可。

下载:demo

参考文献:

  lucene,你也会(7篇)——第一篇 快速入门

  使用Lucene.Net实现全文检索

  WPF地区选择控件(内附下载地址)

  

后记


  其实相同的功能我用查询数据库的方法,也实现过了,但是耗时每次都是100多毫秒。lucene估计有个缓存吧,速度会越来越快,而且经常被查寻的东西优先级别会提高,排在前面。

  以我的经验,写关于美工的文章比逻辑的获得的关注和推荐多得多。我也很想把通通玩Blend美工这个系列写下去,毕竟我大部分的粉丝都来源于这个系列。但是,最近几个月,都在纠结WF、WCF等等逻辑方面的,对美工没什么好的创意。  

  写博客图个什么?不就是作为一个平凡的码农,想要得到更多人的关注和认可,让我觉得自己其实和民工还是有点区别的。

  对了,我之前嵌在博客里的silverlight为什么都显示不出来了?xap文件我都是放在博客园的文件里的。求大神解答。

  

  

通通WPF随笔(1)——基于lucene.NET让ComboBox拥有强大的下拉联想功能的更多相关文章

  1. 通通WPF随笔(4)——通通手写输入法(基于Tablet pc实现)

    原文:通通WPF随笔(4)--通通手写输入法(基于Tablet pc实现) 从我在博客园写第一篇博客到现在已经有1年半了,我的第一篇博客写的就是手写识别,当时,客户需求在应用中加入手写输入功能,由于第 ...

  2. 通通WPF随笔(3)——艺术二维码素材生成器

    原文:通通WPF随笔(3)--艺术二维码素材生成器 最近公司让我开发一个条形码的生成控件,花了半天时间搞定觉得不过瘾,什么年代了该用二维码了吧.于是wiki了一下二维码的资料. 比较常见的就是QR码( ...

  3. 通通WPF随笔(2)——自己制作轻量级asp.net网站服务

    原文:通通WPF随笔(2)--自己制作轻量级asp.net网站服务 大学玩asp.net时就发现VS在Debug时会起一个web服务,这东西也太神奇了服务起得这么快,而相对于IIS又这么渺小. 前几个 ...

  4. 【selenium】基于python语言,如何用select选择下拉框

    在项目测试中遇到了下拉框选择的控件,来总结下如何使用select选择下拉框: 下图是Select类的初始化描述,意思是,给定元素是得是select类型,不是就抛异常.接下来给了例子:要操作这个sele ...

  5. 一款基于jQuery的联动Select下拉框

    今天我们要来分享一款很实用的jQuery插件,它是一个基于jQuery多级联动的省市地区Select下拉框,并且值得一提的是,这款联动下拉框是经过自定义美化过的,外观比浏览器自带的要漂亮许多.另外,这 ...

  6. WebGIS中兴趣点简单查询、基于Lucene分词查询的设计和实现

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.前言 兴趣点查询是指:输入框中输入地名.人名等查询信息后,地图上可 ...

  7. 基于lucene实现自己的推荐引擎

    基于lucene实现自己的推荐引擎 推荐常用算法之-基于内容的推荐 推荐算法

  8. Apache Solr采用Java开发、基于Lucene的全文搜索服务器

    http://docs.spring.io/spring-data/solr/ 首先介绍一下solr: Apache Solr (读音: SOLer) 是一个开源.高性能.采用Java开发.基于Luc ...

  9. 基于lucene的案例开发:查询语句创建PackQuery

    转载请注明出处:http://blog.csdn.net/xiaojimanman/article/details/44656141 http://www.llwjy.com/blogdetail/1 ...

随机推荐

  1. windows 空闲超时 非管理员如何破解

    windows 空闲超时 非管理员如何破解

  2. PHP正则表达式怎么匹配多行

    PHP正则表达式怎么匹配多行 一.总结 1.可以用匹配模式修饰符s来使点匹配所有字符,包括换行符. 二.PHP匹配多行的正则表达式分析 代码如下: <table> <tr>&l ...

  3. 囚徒困境、价格大战与 iPhone 的价格

    静态/动态,完全/不完全: 完全信息静态博弈: 不完全信息静态博弈: 完全信息动态博弈: 不完全信息动态博弈: 囚徒困境实际上反映了一个深刻的哲学问题:个人利益与集体利益的矛盾.个人为了自己利益的最大 ...

  4. DDoS ATTACK PROCESSING APPARATUS AND METHOD IN OPENFLOW SWITCH

    An OpenFlow switch in an OpenFlow environment includes an attack determination module to collect sta ...

  5. NOIP模拟 Date - Tarjan

    题目描述 小Y和小Z好不容易有机会相见啦,可是邪恶的小H却不想让他们相见.现在有一些城市,城市之间有双向路径相连,有路径相连的城市之间可以互相到达.小H可以任意选择一条路径,然后用他的邪恶力量污染这条 ...

  6. MapReduce自定义InputFormat,RecordReader

    MapReduce默认的InputFormat是TextInputFormat,且key是偏移量,value是文本,自定义InputFormat需要实现FileInputFormat,并重写creat ...

  7. 【23.33%】【codeforces 664C】International Olympiad

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  8. Hamcrest 总结

    Junit JUnit框架用一组assert方法封装了一些常用的断言.这些assert方法可以帮我们简化单元测试的编写.这样的话,Junit就可以根据这些断言是否抛出 AssertionFailedE ...

  9. 编译和使用jasper库的一个注意事项

    作者:朱金灿 来源:http://blog.csdn.net/clever101 由于jasper库是一个跨平台库,而Windows的VC编译器和Linux的GCC编译器的头文件并不完全一致(可能因为 ...

  10. ios中 微信点击 某个元素 该元素会闪一下

    -webkit-user-select: none;-webkit-tap-highlight-color: rgba(200,200,200,0);