博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
通通WPF随笔(1)——基于lucene.NET让ComboBox拥有强大的下拉联想功能
阅读量:6005 次
发布时间:2019-06-20

本文共 5087 字,大约阅读时间需要 16 分钟。

原文:

 


 

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

名称:

简拼:

全拼:

区号:

邮编:

              

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

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

XAML:

属性介绍:(该控件继承于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,由于电脑上没有数据库环境,所以只测试了AccessSqlite

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

View Code
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()方法。所以不能重载ExpandoObjectToString()方法。所以这里自定义了一个轻量级的ExpandoObject类,继承于DynamicObject实现。

 代码:

class dyData:DynamicObject        {            public dyData(string colName)            {                this.colName = colName;            }            //ToString时需要输出的属性            public string colName { get; set; }            //用于存储属性名和对应的值            Dictionary
data = new Dictionary
(); //绑定时获取对应属性的值 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直接数据绑定即可。

 

下载:

 

参考文献:

  

  

  

  

后记


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

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

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

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

  

 

 

 

 

  

转载地址:http://mxpmx.baihongyu.com/

你可能感兴趣的文章
【矢量图控件教程】矢量图控件VectorDraw 常见问题整理大全(一)
查看>>
文件系统、服务、防火墙、SELINUX——安全四大金刚
查看>>
RabbitMQ如何保证队列里的消息99.99%被消费?
查看>>
Lync Server 2010的部署系列_第五章 准备 Active Directory 域服务
查看>>
java基本数据类型及运算符小结
查看>>
第一周博客作业
查看>>
Python strip lstrip rstrip使用方法
查看>>
Linux开发工具_1_gcc入门(上)
查看>>
在这里安家了
查看>>
ERP项目更应授人以渔
查看>>
我的友情链接
查看>>
thinkpython2
查看>>
JDK、JRE和JVM的关系
查看>>
String、StringBuffer和StringBuilder的区别
查看>>
【原创】ObjectARX中的代理对象
查看>>
.net中验证码的几种常用方法
查看>>
解决OracleDBConsoleorcl不能启动
查看>>
.net DLL程序集中打包另一个DLL
查看>>
我的友情链接
查看>>
Drupal第三方模块汇集(一)
查看>>