zl程序教程

您现在的位置是:首页 >  后端

当前栏目

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

NetASP思路代码 实现 检索 文本框 复合
2023-06-13 09:14:45 时间

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

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

   

 

一、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文件,如下图:

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

复制代码代码如下:

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

returndeclare("test.FilteringSelect",[FilteringSelect],{

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

//summary:
//覆盖dijit.form._AutoCompleterMixin的同名方法,使FilteringSelect支持displayValueAttr指定textbox最终显示内容,而不是默认显示searchAttr指定的字段内容
_announceOption:function(/*Node*/node){

if(!node){
return;
}
//pullthetextvaluefromtheitemattachedtotheDOMnode
varnewValue;
if(node==this.dropDown.nextButton||
node==this.dropDown.previousButton){
newValue=node.innerHTML;
this.item=undefined;
this.value="";
}else{
varitem=this.dropDown.items[node.getAttribute("item")];
vardisplayAttr=this.displayValueAttr!=null?this.displayValueAttr:this.searchAttr;//此处判断是否配置了自定义属性displayValueAttr

newValue=(this.store._oldAPI?//removegetValue()for2.0(olddojo.dataAPI)
this.store.getValue(item,displayAttr):item[displayAttr]).toString();//将this.searchAttr替换为displayAttr

this.set("item",item,false,newValue);
}
//getthetextthattheusermanuallyentered(cutoffautocompletedtext)
this.focusNode.value=this.focusNode.value.substring(0,this._lastInput.length);
//setupARIAactivedescendant
this.focusNode.setAttribute("aria-activedescendant",domAttr.get(node,"id"));
//autocompletetherestoftheoptiontoannouncechange
this._autoCompleteText(newValue);
},

});
});

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

<%@PageTitle=""Language="C#"AutoEventWireup="true"CodeFile="OrgRelation.aspx.cs"Inherits="OrgRelation"%>

<!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

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

<headid="Head1"runat="server">
<title></title>
<scriptsrc="Scripts/jquery-1.4.1-vsdoc.js"type="text/javascript"></script>
<linkhref="Scripts/dojo/dijit/themes/claro/claro.css"rel="stylesheet"type="text/css"/>
<linkhref="Scripts/dojo/dojo/resources/dojo.css"rel="stylesheet"type="text/css"/>
<scriptsrc="Scripts/dojo/dojo/dojo.js"type="text/javascript"></script>

<scripttype="text/javascript">
//参数设置
require([
"test/FilteringSelect",
"dojo/store/Memory",
"dojo/domReady!"
],function(FilteringSelect,Memory){

varjsonstr="<%=userListStr%>";
varjson=jQuery.parseJSON(jsonstr);
varobj={data:""};
obj["data"]=json;
varselectStore=newMemory(obj);
//创建FilteringSelect
vartestSelect=newFilteringSelect({
id:"testSelect",
name:"test",
value:"",
store:selectStore,
searchAttr:"py",//指定输入文本框进行用来进行检索的字段
labelAttr:"name",//指定下拉菜单中显示的字段
displayValueAttr:"name",//指定选中下拉菜单后显示在输入框中的字段
required:false,
autoComplete:false
},"testSelect");

});

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

functionselblur(){
varguid=dijit.byId("testSelect").attr("value");
alert(guid);
window.location.href="OrgRelation.aspx?userId="+guid;
returnfalse;
}
varsel=dojo.byId("testSelect");
dojo.connect(sel,"onblur",selblur);
};
</script>

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

<divstyle="text-align:center;width:100%;padding-top:100px;font-size:15px;">选择用户:<inputid="testSelect"/>
</div>

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

最后,在页面加载事件中获取用户数据,序列化之后,赋给protected类型的userListstr字段。其中这里引用到微软提供的获取汉字拼音的类库ChnCharInfo.dll,代码请单如下:
复制代码代码如下:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Web;
usingSystem.Web.UI;
usingSystem.Web.UI.WebControls;
usingMicrosoft.International.Converters.PinYinConverter;
usingSystem.Text;
usingSystem.Text.RegularExpressions;
usingSystem.Web.Script.Serialization;

publicpartialclassOrgRelation:System.Web.UI.Page
{
protectedstringuserListStr=string.Empty;

protectedvoidPage_Load(objectsender,EventArgse)
{
if(!IsPostBack)
{
GetUsers();
}
}

//与前台页面Json对象格式对应的类
publicclassUserInfo
{
publicstringname{get;set;}
publicstringid{get;set;}
publicstringpy{get;set;}
}

protectedvoidGetUsers()
{
//获取用户信息,及每项记录的拼音简码
List<User>list=newBLL.User().GetUsers();
List<UserInfo>UserInfoList=newList<UserInfo>();
foreach(Useriteminlist)
{
UserInfouserInfo=newUserInfo();
userInfo.id=item.UserId;
userInfo.name=item.UserName;
userInfo.py=GetPY(item.UserName);
UserInfoList.Add(userInfo);
}
JavaScriptSerializerjsonSerializer=newJavaScriptSerializer();
//执行序列化并赋值
userListStr=jsonSerializer.Serialize(UserInfoList);
}

#region拼音检索的相关方法
///<summary>
///获得一个汉字字符的拼音的字符串集合,并处理声调和空值
///</summary>
///<paramname="ch">汉字字符</param>
///<returns></returns>
publicstaticList<string>GetPinyins(charch)
{
List<string>list=newList<string>();
ChineseCharcc=newChineseChar(ch);//获得包含汉字信息的对象
foreach(stringitemincc.Pinyins)
{
if(item!=null)
{
stringtemp=item.Substring(0,item.Length-1);
if(!list.Contains(temp))
{
list.Add(temp);
}
}
}
returnlist;
}
///<summary>
///得到一个词组的拼音的首字母字符串(多音取第一个)
///</summary>
///<returns></returns>
publicstaticstringGetPY(stringstr)
{
Regexreg=newRegex(@"[\u4e00-\u9fa5]");
StringBuildersb=newStringBuilder();
for(inti=0;i<str.Length;i++)
{
stringch=str[i].ToString();
if(reg.IsMatch(ch))
{
strings=GetPinyins(str[i])[0];
sb.Append(s[0]);
}
else
{
sb.Append(ch);
}
}
returnsb.ToString();
}
#endregion
}

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

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

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

需要用到的相关组件和引用的类库:Jquery-UI、汉字拼音转换语言包类库ChnCharInfo.dll和Json对象序列化类库Newtonsoft.Json.dll,如下所示:

 

1.WebForm的aspx页面实现:

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

复制代码代码如下:
<scripttype="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控件中,其服务端实现与本次讨论的内容无关,代码就不贴出来了。

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

复制代码代码如下:
<%@PageTitle=""Language="C#"AutoEventWireup="true"CodeFile="OrgRelation.aspx.cs"
Inherits="OrgRelation"%>

<!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<htmlxmlns="http://www.w3.org/1999/xhtml">
<headid="Head1"runat="server">
<title></title>
<scriptsrc="Scripts/jquery-1.8.2.js"type="text/javascript"></script>
<scriptsrc="Scripts/jquery-ui-1.9.0.custom.js"type="text/javascript"></script>
<linkhref="css/ui-lightness/jquery-ui-1.9.0.custom.css"rel="stylesheet"type="text/css"/>
<scripttype="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>
<formid="form2"method="post"action="./OrgRelation.aspx"name="sendForm"></form>
<formid="Form1"method="post"runat="server">
<inputtype="hidden"id="hidUserId"name="hidUserId"value="<%=currentUserId%>"/>
<inputtype="hidden"id="hidUserName"name="hidUserName"value="<%=currentUserName%>"/>

<asp:ScriptManagerID="ScriptManager1"runat="server">
</asp:ScriptManager>
<divid="outline">
<divalign="center"id="title">
<strong>编辑用户部门关系</strong>
</div>
<divid="main">
<tablealign="center">
<tr>
<td>
<div>
<b>选择用户:</b> 
<asp:UpdatePanelID="UpdatePanel2"runat="server">
<ContentTemplate>
<inputtype="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>
<tdvalign="top"width="41%">
<divid="left">
<asp:UpdatePanelID="UpdatePanel1"runat="server">
<ContentTemplate>
<asp:TreeViewID="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>
<tdalign="center"valign="middle"width="18%">
<p>

<asp:ButtonID="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:ButtonID="btnRemoveOrg"runat="server"Width="85px"Text="<<移除部门"Height="22px"
BorderStyle="Solid"BorderColor="DarkGray"BackColor="GhostWhite"Font-Size="9pt"
OnClick="btnRemoveOrg_Click"></asp:Button></p>

</td>
<tdvalign="top"align="center"width="41%">
<divid="right">
<asp:ListBoxID="LBOrg"runat="server"Width="300px"Height="350px"Rows="13"BackColor="AliceBlue"
Font-Size="11pt"SelectionMode="Multiple">
</asp:ListBox>
</div>
</td>
</tr>
</table>
</div>
<br/>
<divalign="center"id="bottom">
<asp:ButtonID="btnBack"runat="server"Text="·返回·"BackColor="#f8f8ff"/>  
<asp:ButtonID="btnSave"runat="server"Text="·保存·"BackColor="#f8f8ff"
onclick="btnSave_Click"/>
</div>
</div>
</form>
</body>
</html>

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

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

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

复制代码代码如下:
voidApplication_Start(objectsender,EventArgse)
{
Application.Lock();
Application["User"]=GetUsers();
Application.UnLock();
}

获取用户信息的GetUser方法中,同时完成了拼音简码的获取,代码如下:
复制代码代码如下:
protectedList<string>GetUsers()
{
List<Model.User>list=newBLL.User().GetUsers();
List<string>UserList=newList<string>();
foreach(Model.Useriteminlist)
{
UserList.Add(item.Id+"|"+item.Name+"|"+GetPY(item.Name).Replace("","").ToLower());
}
returnUserList;
}

///<summary>
///获得一个汉字字符的拼音的字符串集合,并处理声调和空值
///</summary>
///<paramname="ch">汉字字符</param>
///<returns></returns>
publicstaticList<string>GetPinyins(charch)
{
List<string>list=newList<string>();
Microsoft.International.Converters.PinYinConverter.ChineseCharcc=newMicrosoft.International.Converters.PinYinConverter.ChineseChar(ch);//获得包含汉字信息的对象
foreach(stringitemincc.Pinyins)
{
if(item!=null)
{
stringtemp=item.Substring(0,item.Length-1);
if(!list.Contains(temp))
{
list.Add(temp);
}
}
}
returnlist;
}
///<summary>
///得到一个词组的拼音的首字母字符串(多音取第一个)
///</summary>
///<returns></returns>
publicstaticstringGetPY(stringstr)
{
Regexreg=newRegex(@"[\u4e00-\u9fa5]");
StringBuildersb=newStringBuilder();
for(inti=0;i<str.Length;i++)
{
stringch=str[i].ToString();
if(string.IsNullOrEmpty(ch))
{

}
elseif(reg.IsMatch(ch))
{
strings=GetPinyins(str[i])[0];
sb.Append(s[0]);
}
else
{
sb.Append(ch);
}
}
returnsb.ToString();
}

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

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

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

复制代码代码如下:
<%@WebHandlerLanguage="C#"Class="GetUser"%>

usingSystem;
usingSystem.Web;
usingBLL;
usingSystem.Collections.Generic;
usingSystem.Text.RegularExpressions;
usingSystem.Web.Script.Serialization;
usingMicrosoft.International.Converters.PinYinConverter;

publicclassGetUser:JavaScriptSerializer,IHttpHandler
{
publicvoidProcessRequest(HttpContextcontext)
{
inti=0;
List<string>strlist=context.Application["User"]asList<string>;
stringinputStr=context.Request.QueryString.Get("term").ToLower();
List<UserItem>userList=newList<UserItem>();

foreach(stringstrinstrlist)
{
string[]userArr=str.Split("|");
if(i<10)
{
Regexreg=newRegex(@"^"+inputStr);
if(reg.IsMatch(userArr[2])||reg.IsMatch(userArr[1]))
{
UserItemitem=newUserItem();
item.id=userArr[0];
item.label=userArr[1];
item.value=userArr[2];
userList.Add(item);
i++;
}
}
else
{
break;
}
}

context.Response.ContentType="application/json";
stringoutput=Newtonsoft.Json.JsonConvert.SerializeObject(userList);
context.Response.Write(output);
}

publicboolIsReusable
{
get
{
returnfalse;
}
}
}

publicclassUserItem
{
publicstringid{get;set;}
publicstringlabel{get;set;}
publicstringvalue{get;set;}
}

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

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

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