欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

ASP.Net中英文复合检索文本框实现思路及代码

程序员文章站 2024-03-05 09:22:00
前段时间,写一个用户部门的管理页面,需要对后台获取的用户数据实现英汉检索功能。  同时,选定一个选项之后,需要触发事件与后台交互,将该用户所在的部门显示到页面右边的l...

前段时间,写一个用户部门的管理页面,需要对后台获取的用户数据实现英汉检索功能。 

ASP.Net中英文复合检索文本框实现思路及代码

同时,选定一个选项之后,需要触发事件与后台交互,将该用户所在的部门显示到页面右边的listbox控件中。

   ASP.Net中英文复合检索文本框实现思路及代码

  ASP.Net中英文复合检索文本框实现思路及代码

一、dojo的filteringselect组件实现拼音检索功能

在网上有不少相关的介绍,其中比较经典的有"海盗乱语"的关于重写dojo的filteringselect组件实现拼音检索功能的介绍(地址http://cosbor.web-144.com/?p=38、http://cosbor.web-144.com/?p=52)。由于作者的demo后台以及pinyin4j的jar包都是基于java平台的,本人花了一点时间将其实现在.net平台下,并成功的实现了filteringselect选中事件的注册。实现原理请详细参考"海盗乱语"博客中的分析,这里对.net平台下的实现思路做简要说明,并贴出源码供大家参考(在此对作者提供的思路表示感谢!):

首先,引入dojo工具包,在dojo目录下添加一个"test"文件夹,新建一个filteringselect.js文件,如下图:

ASP.Net中英文复合检索文本框实现思路及代码

filteringselect.js文件的作用是重写filteringselect组件,"海盗乱语"的博文中给出了的代码清单,为方便起见转贴如下:

复制代码 代码如下:

define([
"dojo/_base/declare", // declare,
"dojo/dom-attr", // domattr.get
"dijit/form/filteringselect"
], function(declare, domattr ,filteringselect){

return declare("test.filteringselect", [filteringselect], {

displayvalueattr:null, //新增一个自定义属性,用于指定filteringselect的textbox中最终显示内容的属性字段

// summary:
// 覆盖dijit.form._autocompletermixin的同名方法,使filteringselect支持displayvalueattr指定textbox最终显示内容,而不是默认显示searchattr指定的字段内容
_announceoption: function(/*node*/ node){

if(!node){
return;
}
// pull the text value from the item attached to the dom node
var newvalue;
if(node == this.dropdown.nextbutton ||
node == this.dropdown.previousbutton){
newvalue = node.innerhtml;
this.item = undefined;
this.value = '';
}else{
var item = this.dropdown.items[node.getattribute("item")];
var displayattr = this.displayvalueattr!=null?this.displayvalueattr:this.searchattr;//此处判断是否配置了自定义属性displayvalueattr

newvalue = (this.store._oldapi ? // remove getvalue() for 2.0 (old dojo.data api)
this.store.getvalue(item, displayattr) : item[displayattr]).tostring();//将this.searchattr替换为displayattr

this.set('item', item, false, newvalue);
}
// get the text that the user manually entered (cut off autocompleted text)
this.focusnode.value = this.focusnode.value.substring(0, this._lastinput.length);
// set up aria activedescendant
this.focusnode.setattribute("aria-activedescendant", domattr.get(node, "id"));
// autocomplete the rest of the option to announce change
this._autocompletetext(newvalue);
},

});
});

然后,新建一个webform页面,放置一个filteringselect控件,数据源取值为页面类继承过来的userliststr字段,页面前台代码如下: 
复制代码 代码如下:

<%@ page title="" language="c#" autoeventwireup="true" codefile="orgrelation.aspx.cs" inherits="orgrelation" %>

<!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head id="head1" runat="server">
<title></title>
<script src="scripts/jquery-1.4.1-vsdoc.js" type="text/javascript"></script>
<link href="scripts/dojo/dijit/themes/claro/claro.css" rel="stylesheet" type="text/css" />
<link href="scripts/dojo/dojo/resources/dojo.css" rel="stylesheet" type="text/css" />
<script src="scripts/dojo/dojo/dojo.js" type="text/javascript"></script>

<script type="text/javascript">
//参数设置
require([
'test/filteringselect',
'dojo/store/memory',
'dojo/domready!'
], function (filteringselect, memory) {

var jsonstr = '<%=userliststr%>';
var json = jquery.parsejson(jsonstr);
var obj = {data:""};
obj['data'] = json;
var selectstore = new memory(obj);
//创建filteringselect
var testselect = new filteringselect({
id: "testselect",
name: "test",
value: "",
store: selectstore,
searchattr: 'py', //指定输入文本框进行用来进行检索的字段
labelattr: 'name', //指定下拉菜单中显示的字段
displayvalueattr: 'name', //指定选中下拉菜单后显示在输入框中的字段
required: false,
autocomplete: false
}, "testselect");

});

//注册失去焦点事件
window.onload = function () {

function selblur() {
var guid = dijit.byid('testselect').attr('value');
alert(guid);
window.location.href = "orgrelation.aspx?userid=" + guid;
return false;
}
var sel = dojo.byid("testselect");
dojo.connect(sel, "onblur", selblur);
};
</script>

</head>
<body>
<form id="form1" method="post" runat="server">
<div align="center" id="title">
<strong>编辑用户部门关系</strong>
</div>

<div style="text-align: center;width: 100%;padding-top: 100px;font-size:15px;">选择用户:<input id="testselect"/>
</div>

</form>
</body>
</html>

最后,在页面加载事件中获取用户数据,序列化之后,赋给protected类型的userliststr字段。其中这里引用到微软提供的获取汉字拼音的类库chncharinfo.dll,代码请单如下:
复制代码 代码如下:

using system;
using system.collections.generic;
using system.linq;
using system.web;
using system.web.ui;
using system.web.ui.webcontrols;
using microsoft.international.converters.pinyinconverter;
using system.text;
using system.text.regularexpressions;
using system.web.script.serialization;

public partial class orgrelation : system.web.ui.page
{
protected string userliststr = string.empty;

protected void page_load(object sender, eventargs e)
{
if (!ispostback)
{
getusers();
}
}

//与前台页面json对象格式对应的类
public class userinfo
{
public string name { get; set; }
public string id { get; set; }
public string py { get; set; }
}

protected void getusers()
{
//获取用户信息,及每项记录的拼音简码
list<user> list =new bll.user().getusers();
list<userinfo> userinfolist = new list<userinfo>();
foreach (user item in list)
{
userinfo userinfo= new userinfo();
userinfo.id = item.userid;
userinfo.name = item.user name;
userinfo.py = getpy(item.username);
userinfolist .add(userinfo);
}
javascriptserializer jsonserializer = new javascriptserializer();
//执行序列化 并赋值
userliststr = jsonserializer.serialize(userinfolist);
}

#region 拼音检索的相关方法
/// <summary>
/// 获得一个汉字字符的拼音的字符串集合,并处理声调和空值
/// </summary>
/// <param name="ch">汉字字符</param>
/// <returns></returns>
public static list<string> getpinyins(char ch)
{
list<string> list = new list<string>();
chinesechar cc = new chinesechar(ch); //获得包含汉字信息的对象
foreach (string item in cc.pinyins)
{
if (item != null)
{
string temp = item.substring(0, item.length - 1);
if (!list.contains(temp))
{
list.add(temp);
}
}
}
return list;
}
/// <summary>
/// 得到一个词组的拼音的首字母字符串(多音取第一个)
/// </summary>
/// <returns></returns>
public static string getpy(string str)
{
regex reg = new regex(@"[\u4e00-\u9fa5]");
stringbuilder sb = new stringbuilder();
for (int i = 0; i < str.length; i++)
{
string ch = str[i].tostring();
if (reg.ismatch(ch))
{
string s = getpinyins(str[i])[0];
sb.append(s[0]);
}
else
{
sb.append(ch);
}
}
return sb.tostring();
}
#endregion
}

这样拼音检索的功能就完成了。不过有两点不尽人意的地方:1.使用拼音检索后,不好再使用中文检索,2.网上查了很久,没有选中项改变事件介绍,代码中只是注册了一个失去焦点事件,在与后台交互方面不太方便(可能是本人对dojo事件不熟,欢迎对dojo api有研究的大侠指点)。

二、jqueryui的autocomplete插件实现拼音检索功能

其实jqueryui也提供了一个非常好用的插件--autocomplete,它与chncharinfo.dll类库配合使用,不仅能实现同样优秀的检索功能,而且能够很好的解决上述两个问题。不妨来看看:

需要用到的相关组件和引用的类库:jquery-ui 、汉字拼音转换语言包类库chncharinfo .dll和json对象序列化类库newtonsoft.json.dll,如下所示:

 ASP.Net中英文复合检索文本框实现思路及代码

1.webform的aspx页面实现:

首先引入jquery-1.8.2.js、jquery-ui-1.9.0.custom.js、jquery-ui-1.9.0.custom.css,然后在页面加载完成的事件中写如下脚本:

复制代码 代码如下:

<script type="text/javascript">
$(function () {
$("#selcompate").autocomplete({
source: "getuser.ashx",
minlength: 1,
//以下为选中事件
select: function (event, ui) {
temp = ui.item;
$("#hidcontactid").val(temp.id);
$("#hidcontactname").val(temp.label);
$("#form2").attr("action", "./orgrelation.aspx?contactid=" + temp.id + "&contactname=" + temp.label);
$("#form2").submit();
}
});
$("#selcompate").val($("#hidcontactname").val())
});
</script>

其中第4行的 source: "getuser.ashx",是指键入字符后,发送异步请求的地址,getuser.ashx负责向请求的客户端提供满足json格式的用户信息;第5行的minlength: 是输入到几个字符时开始发送异步请求;第7行的select: function(event, ui){}即选中事件,ui.item表示被选中的项;第8-9行的隐藏域存值,是为了页面刷新后能重新获取该选中项的相关信息,重新写回页面以备用;第10-11行以当前选中项的id和label被为参数向orgrelation.aspx发送post请求,是实现将选中用户的所在部门查询处来,显示到页面右侧的listbox控件中,其服务端实现与本次讨论的内容无关,代码就不贴出来了。

页面的完整代码清单如下:

复制代码 代码如下:

<%@ page title="" language="c#" autoeventwireup="true" codefile="orgrelation.aspx.cs"
inherits="orgrelation"%>

<!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="head1" runat="server">
<title></title>
<script src="scripts/jquery-1.8.2.js" type="text/javascript"></script>
<script src="scripts/jquery-ui-1.9.0.custom.js" type="text/javascript"></script>
<link href="css/ui-lightness/jquery-ui-1.9.0.custom.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
$(function () {
$("#selcompate").autocomplete({
source: "getuser.ashx",
minlength: 1,
//以下为选中事件
select: function (event, ui) {
temp = ui.item;
$("#hiduserid").val(temp.id);
$("#hidusername").val(temp.label);
$("#form2").attr("action", "./orgrelation.aspx?userid=" + temp.id + "&username=" + temp.label);
$("#form2").submit();
}
});
$("#selcompate").val($("#hidusername").val())
});
</script>
</head>
<body>
<form id="form2" method="post" action="./orgrelation.aspx" name="sendform"></form>
<form id="form1" method="post" runat="server" >
<input type="hidden" id="hiduserid" name="hiduserid" value="<%=currentuserid%>" />
<input type="hidden" id="hidusername" name="hidusername" value="<%=currentusername%>"/>

<asp:scriptmanager id="scriptmanager1" runat="server">
</asp:scriptmanager>
<div id="outline">
<div align="center" id="title">
<strong>编辑用户部门关系</strong>
</div>
<div id="main">
<table align="center">
<tr>
<td>
<div>
<b>选择用户:</b> 
<asp:updatepanel id="updatepanel2" runat="server">
<contenttemplate>
<input type="text" id="selcompate" style="line-height: 10px; margin-top: 0px;
margin-left: 0px; height: 23px;"
runat="server" />
</contenttemplate>
</asp:updatepanel><br />
<b>选择部门:</b>
</div>
<br />
</td>
<td>
</td>
<td>
</td>
</tr>
<tr>
<td valign="top" width="41%">
<div id="left">
<asp:updatepanel id="updatepanel1" runat="server">
<contenttemplate>
<asp:treeview id="treevieworgdata" runat="server" font-names="微软雅黑" height="385px"
font-size="11pt" forecolor="black" backcolor="aliceblue" ontreenodecollapsed="treevieworgdata_treenodecollapsed"
ontreenodeexpanded="treevieworgdata_treenodeexpanded" showcheckboxes="all">
</asp:treeview>
</contenttemplate>
</asp:updatepanel>
</div>
</td>
<td align="center" valign="middle" width="18%">
<p>

<asp:button id="btnaddorg" runat="server" width="85px" text="添加部门 >>" height="22px"
borderstyle="solid" bordercolor="darkgray" backcolor="ghostwhite" font-size="9pt"
onclick="btnaddorg_click"></asp:button></p>
<p>
<asp:button id="btnremoveorg" runat="server" width="85px" text="<< 移除部门" height="22px"
borderstyle="solid" bordercolor="darkgray" backcolor="ghostwhite" font-size="9pt"
onclick="btnremoveorg_click"></asp:button></p>

</td>
<td valign="top" align="center" width="41%">
<div id="right">
<asp:listbox id="lborg" runat="server" width="300px" height="350px" rows="13" backcolor="aliceblue"
font-size="11pt" selectionmode="multiple" >
</asp:listbox>
</div>
</td>
</tr>
</table>
</div>
<br />
<div align="center" id="bottom">
<asp:button id="btnback" runat="server" text="·返 回·" backcolor="#f8f8ff" />  
<asp:button id="btnsave" runat="server" text="·保 存·" backcolor="#f8f8ff"
onclick="btnsave_click" />
</div>
</div>
</form>
</body>
</html>

2.global.asax中用户数据的准备

由于这里的用户数据不经常变化,考虑到搜索是需要频繁的向服务端请求数据,因此将用户数据存入了application中,这样搜索时直接从application中取,不用每次去数据库查询。

application对象的赋值是在全局应用程序global.asax的 application_start事件中完成的,代码如下:

复制代码 代码如下:

void application_start(object sender, eventargs e)
{
application.lock();
application["user"] = getusers();
application.unlock();
}

获取用户信息的getuser方法中,同时完成了拼音简码的获取,代码如下:
复制代码 代码如下:

protected list<string> getusers()
{
list<model.user> list = new bll.user().getusers();
list<string> userlist = new list<string>();
foreach (model.user item in list)
{
userlist .add(item.id+"|"+item.name+"|"+getpy(item.name).replace(" ","").tolower());
}
return userlist ;
}

/// <summary>
/// 获得一个汉字字符的拼音的字符串集合,并处理声调和空值
/// </summary>
/// <param name="ch">汉字字符</param>
/// <returns></returns>
public static list<string> getpinyins(char ch)
{
list<string> list = new list<string>();
microsoft.international.converters.pinyinconverter.chinesechar cc = new microsoft.international.converters.pinyinconverter.chinesechar(ch); //获得包含汉字信息的对象
foreach (string item in cc.pinyins)
{
if (item != null)
{
string temp = item.substring(0, item.length - 1);
if (!list.contains(temp))
{
list.add(temp);
}
}
}
return list;
}
/// <summary>
/// 得到一个词组的拼音的首字母字符串(多音取第一个)
/// </summary>
/// <returns></returns>
public static string getpy(string str)
{
regex reg = new regex(@"[\u4e00-\u9fa5]");
stringbuilder sb = new stringbuilder();
for (int i = 0; i < str.length; i++)
{
string ch = str[i].tostring();
if (string.isnullorempty(ch))
{

}
else if (reg.ismatch(ch))
{
string s = getpinyins(str[i])[0];
sb.append(s[0]);
}
else
{
sb.append(ch);
}
}
return sb.tostring();
}

至于application与数据库中数据的一致的考虑,可提供一个一般处理程序updateapplication.ashx负责更新application(代码与global.asax中基本相同),当数据库发生变化时,访问updateapplication.ashx即可更新application["contact"]对象。

3.getuser.ashx中返回符合检索条件的数据

getuser.ashx中响应搜索事件的服务端代码清单如下:

复制代码 代码如下:

<%@ webhandler language="c#" class="getuser" %>

using system;
using system.web;
using bll;
using system.collections.generic;
using system.text.regularexpressions;
using system.web.script.serialization;
using microsoft.international.converters.pinyinconverter;

public class getuser :javascriptserializer,ihttphandler
{
public void processrequest(httpcontext context)
{
int i = 0;
list<string> strlist = context.application["user"] as list<string>;
string inputstr = context.request.querystring.get("term").tolower();
list<useritem> userlist = new list<useritem>();

foreach (string str in strlist)
{
string[] userarr = str.split('|');
if (i < 10)
{
regex reg = new regex(@"^" + inputstr);
if (reg.ismatch(userarr[2]) || reg.ismatch(userarr[1]))
{
useritem item = new useritem();
item.id = userarr[0];
item.label = userarr[1];
item.value = userarr[2];
userlist.add(item);
i++;
}
}
else
{
break;
}
}

context.response.contenttype = "application/json";
string output = newtonsoft.json.jsonconvert.serializeobject(userlist);
context.response.write(output);
}

public bool isreusable
{
get
{
return false;
}
}
}

public class useritem
{
public string id { get; set; }
public string label { get; set; }
public string value { get; set; }
}

第17行是获取文本框中输入的检索字符串inputstr,这里使用正则表达式对获取名称以inputstr开头的记录(中文检索)或者拼音简码以inputstr开头的记录(拼音检索)。如果需要模糊检索功能,可以修改第25行的正则表达式为:regex reg = new regex(inputstr);即可。如果需要更多字段的复合检索(例如用户手机号,邮箱地址等),也只要application对像赋值时获取相关的字段信息,在26行的if判断中增加相应匹配项即可。

其中useritem是为页面提供json对象的类,label是必须字段,搜索框中显示的内容即该字段的值。得到符合条件的数据集合后,需要使用newtonsoft.json.jsonconvert的serializeobject方法进行序列化,再返回给客户端。

到此,即实现了本文开篇的贴图效果。