几个月前,我扩展了Atlas CTP时期的的AutoCompleteBehavior,到了ASP.NET AJAX正式版之后这个扩展自然就不能用了。其实这段时间内有不少朋友问我该如何做到像Google Suggest那样带丰富样式的自动补全功能,但是由于各种原因(比如时间不够,还有现在的AutoCompleteBehavior复杂的许多,或者仅仅是“懒”……),我没有深入地研究它,更别提对它的扩展了。
最近手头正好有些时间,也就逼迫自己耐着性子读了读AutoCompleteBehavior的代码。不得不承认Ajax Control Tookit本身也在不停的发展之中,现在无论服务器端还是客户端都提供了非常强大的基础组件,解决了大量常见问题,使得开发工作变得简单了许多。与此形成鲜明对比的是文档的缺乏,建议对于深入ASP.NET AJAX感兴趣的朋友读一下Ajax Control Toolkit的代码,这对于您理解ASP.NET的控件模型与客户端组件的开发大有碑益。
我扩展了现有的AutoCompleteBehavior,使AutoComplete的功能能够轻松支持丰富的样式。我在这里暂时不对实现方法进行分析,不过大家可以下载代码并进行一些测试,如果有任何问题还可以反馈给我。另外,我认为目前StyledAutoCompleteBehavior的设计还不够灵活,如果有什么需要但是无法实现的功能请您告诉我,也欢迎大家给我一些功能设计方面的建议。自动补全是一个很常用的功能,可惜Ajax Control Toolkit中提供的功能实在不够用。
在我的扩展中,StyledAutoCompleteExtender继承了AutoCompleteExtender,StyledAutoCompleteBehavior继承了AutoCompleteBehavior,在编写时我也尽可能的保持了原有的功能不变,因此大家在使用时完全可以将AutoCompleteExtender的标签直接改为StyledAutoComplteExtender而不会影响到任何功能。与AutoCompleteExtender相比,StyledAutoCompleteExtender多了一个属性ItemTemplate用于指定自动补全中每一项的模板。例如我们要实现Google Suggest那样的功能,则需要这样使用StyledAutoCompleteExtender:
<jeffz:StyledAutoCompleteExtender runat="server" BehaviorID="AutoCompleteEx" ID="autoComplete1" TargetControlID="myTextBox" ServicePath="AutoComplete.asmx" ServiceMethod="GetSearchCompletionList" MinimumPrefixLength="2" CompletionInterval="1000" EnableCaching="true" CompletionSetCount="10" CompletionListCssClass="completionListElement" CompletionListItemCssClass="listItem" CompletionListHighlightedItemCssClass="highlightedListItem"> <ItemTemplate> <span style="float:left;" class="keywords">{0}</span> <span style="float:right;" class="result">{1} results</span> <div style="clear:both;"></div> </ItemTemplate> </jeffz:StyledAutoCompleteExtender>
请注意ItemTemplate里的内容,它将作为自动补全每一项的HTML。而诸如{0}、{1}等则作为占位符,最终在显示时将会使用服务器端返回的内容进行替换。为了配合这个功能,服务器端的Web Service方法返回值也有所变化:
[WebMethod] public IList<object[]> GetSearchCompletionList(string prefixText, int count) { if (count == 0) { count = 10; } Random random = new Random(); IList<object[]> items = new List<object[]>(count); for (int i = 0; i < count; i++) { char c1 = (char)random.Next(65, 90); char c2 = (char)random.Next(97, 122); char c3 = (char)random.Next(97, 122); items.Add(new object[] { prefixText + c1 + c2 + c3, random.Next(10000, 300000) }); } return items; }
方法的返回值变成了一个存放object数组的列表,每个object数组将会作为自动补全中每一项的信息发送到客户端。object数组的每个元素将用于替换模板中的占位符(事实上,我使用了String.format方法来获得每一项的HTML,因此事实上您也可以在这里使用本地化的功能等等)。
模拟Google Suggest的效果如下(点击这里查看示例):
新的控件将“补全的内容”和“显示的内容”进行了分离。目前的控件将object数组的第一个元素(下标为0)作为“补全的内容”,在显示的时候,我们可以将其忽略。例如,下面的代码将会模拟Windows Live Mail中Email提示的功能(事实上,Live Mail的这部分自动补全是纯客户端功能,我这里模拟的仅仅是“样式”)。
<head id="Head1" runat="server"> <title>Untitled Page</title> <style type="text/css"> .completionListElement { visibility : hidden; margin : 0px!important; background-color : inherit; color : windowtext; border : buttonshadow; border-width : 1px; border-style : solid; cursor : pointer; overflow : auto; text-align : left; list-style-type : none; font-family : Verdana; font-size: 11px; padding : 0; } .listItem { background-color: white; padding : 1px; } .highlightedListItem { background-color: #e9f5f7; padding : 1px; } </style> </head> <body> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <asp:TextBox runat="server" ID="myTextBox" Width="500" style="height:14px; border: solid 1px gray; font-family:Verdana; font-size: 11px;" /> <jeffz:StyledAutoCompleteExtender runat="server" BehaviorID="AutoCompleteEx" ID="autoComplete1" TargetControlID="myTextBox" ServicePath="AutoComplete.asmx" ServiceMethod="GetEmailCompletionList" MinimumPrefixLength="2" CompletionInterval="1000" EnableCaching="true" CompletionSetCount="10" CompletionListCssClass="completionListElement" CompletionListItemCssClass="listItem" CompletionListHighlightedItemCssClass="highlightedListItem" DelimiterCharacters=",;"> <ItemTemplate>{1}</ItemTemplate> </jeffz:StyledAutoCompleteExtender> </form> </body>
在这里,ItemTemplate的内容很简单,只是将服务器端返回的每个object数组的第二个元素显示在页面上,而第一个元素则作为补全的文本。它对应的Web Service方法如下所示:
private static string[] emails = new string[] { "\"jeffrey zhao at yahoo\" <jeffz@yahoo.com>", "\"jeffrey zhao at yahoo china\" <jeffz@yahoo.com.cn>", "\"jeffrey zhao at live mail\" <jeffz@live.com>", "\"jeffrey zhao at gmail\" <jeffz@gmail.com>" }; [WebMethod] public IList<object[]> GetEmailCompletionList(string prefixText, int count) { IList<object[]> items = new List<object[]>(); prefixText = prefixText.Trim(); foreach (string email in emails) { if (email.Contains(prefixText)) { string encoded = email.Replace(prefixText, "<b>" + prefixText + "</b>"); items.Add(new object[] { HttpUtility.HtmlDecode(email) + ";", encoded }); } } return items; }
服务器端传回的每个object数组长度为2,第一个元素用于自动补全,第二个元素用于显示,因此需要将关键字部分进行加粗。使用效果如下(点击这里查看示例):
另外,正像Live Mail的功能一样,StyleAutoCompleteBehavior也支持输入多个Email——这是新版AutoCompleteBehavior提供的功能,请注意AutoCompleteBehavior的DelimiterCharacters属性,它是一个字符串,字符串中的每个字符即为分隔符。
目前StyledAutoCompleteBehavior只在FireFox和IE下进行了测试。
点击这里查看Google Suggest模拟示例
点击这里查看Windows Live Mail模拟示例
点击这里下载StyleAutoCompleteExtender/Behavior控件以及示例代码。