I have been wondering how the drop-down Lenovo function of Baidu and Gu Ge search boxes is implemented? Are you constantly querying databases? I don't know how they are so efficient. Later, I had no intention of encountering the "lushen" in the blog Park. The search engine sounds very high. So after studying it for a while, the drop-down Lenovo control of WPF was generated.
Name:
Simple competition:
Full competition:
Area code:
Zip code:
So powerful functional code will be complicated? No ~ The code is just a few words.
The interface is as follows: (the number following the drop-down box is the query delay, and the visible efficiency is still very high)
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>
Attribute description: (this control inherits from ComboBox, but has four more attributes)
Url: Set the folder where the index is located (I will introduce how to create the index later)
ColumnNames: Set the name of the column to be retrieved
TextName: select the column name displayed in text after the drop-down list
MaxItems: the maximum number of items displayed in the drop-down box (if there are too many items displayed, there will be latency. The test latency is caused by the change of the data set in the background banding and the new interface, it's not about lucene's efficiency)
ItemTemplate: You can understand it when using WPF. Set the layout of data in the drop-down list. In this way, we have high scalability and flexibility.
1. Overall Thinking
(1) create a lucene index: search for a database in a National City on the internet, extract it using code, and create indexes for each column in it.
(2) query index: You can use the lucene PrefixQuery class to construct a query statement to query the entire table by prefix.
(3) ComboBox binding: bind the data source to the ObservableCollection <dynamic> set (automatic notification, convenient ), each item is an object dynamically constructed based on each query result. Therefore, dynamic runtime Parsing is used.
2. Detailed Design
I will not elaborate on the basic knowledge here. Please refer to the final references in this article.
1. Create a lucene Index
I found a comprehensive Access method when searching for the National Urban database on the Internet, so I specifically wrote the index creation function:
(In the past, the general database Access layer was quite popular. I wrote a general database DBHelper Based on reflection. Since there is no database environment on the computer, I only tested Access and Sqlite)
In fact, it is based on the query results to add lucene indexes to the columns for which the index is to be created. The Code is as follows:
View Code
Private void Button_Click_1 (object sender, RoutedEventArgs e) {// set the index folder var directory = FSDirectory. getDirectory (DirTextBox. text, true); // create an index and use StandardAnalyzer to perform sentence segmentation IndexWriter indexWriter = new IndexWriter (directory, new StandardAnalyzer (); var columnName = ColumnNameTextBox. text. split (','); // set the database connection string 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 () {// create Document doc = new Document (); // Add the field 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 (); // optimize indexWriter for the index file. optimize (); indexWriter. close (); MessageBox. show ("Index created ");}
2. query Indexes
You can use the PrefixQuery class to construct lucene query, as shown below:
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. shocould);} // query. parse: inject query condition var hits = search. search (query );
3. Bind a data source to ComboBox
The data source is an ObservableCollection <dynamic> type set. In the background, we only need to dynamically construct each query object and add it to the set. ExpandoObject cannot be used when initializing dynamic objects. Although ExpandoObject is convenient, it is a closed class and cannot be inherited. When one of the selected items is displayed in the text box, ComboBox actually executes the ToString () method of the selected data source. Therefore, the ToString () method of ExpandoObject cannot be reloaded. Therefore, a lightweight ExpandoObject class is defined here, inherited from the DynamicObject implementation.
Code:
Class dyData: DynamicObject {public dyData (string colName) {this. public string colName {get; set;} // attribute to be output when colName = colName;} is used to store the attribute name and the corresponding value Dictionary <string, object> data = new Dictionary <string, object> (); // obtain the value of the corresponding attribute public override bool TryGetMember (GetMemberBinder binder, out object result) {return data. tryGetValue (binder. name, out result);} // used to add attributes and the corresponding value public void SetValue (string name, object value) {data. add (name, value) ;}// rewrite Tostring method public override string ToString () {try {return data [colName]. toString ();} catch (Exception ex) {MessageBox. show ("the column name cannot be found" + colName, "An error occurred while setting the name of the item to be displayed in text", MessageBoxButton. OK, MessageBoxImage. error); return null ;}}}
In this way, a simple ExpandoObject is implemented. Next, traverse the query results, use SetValue to dynamically create object attributes, and add them to the ObservableCollection <dynamic> data set. ComboBox can directly bind data.
Download: demo
References:
Lucene, you will also (7)-First Quick Start
Full-text search using Lucene. Net
WPF region selection control (included)
Postscript
In fact, I used the database query method to implement the same function, but it took more than 100 milliseconds each time. Lucene has a cache. The cache speed will get faster and faster, and the priority of frequently searched items will increase.
In my experience, writing an article about the artist is much more concerned and recommended than the logic. I would also like to write down the Blend Artist Series. After all, most of my fans come from this series. However, in recent months, we have been struggling with logic such as WF and WCF, and there is no good idea for art artists.
What are blog posts? It is not just an ordinary coders who want to get more people's attention and approval, which makes me feel that I am actually a little different from migrant workers.
By the way, why can't I see silverlight embedded in my blog? Xap files are all stored in the blogs. Please help me.