Hello World
Spiga

出于对Atlas自带AutoCompleteBehavior的不满,自定义了一个支持模版的AutoCompleteBehavior

2006-10-20 03:05 by 老赵, 3592 visits
  Atlas自带的AutoCompleteBehavior实在不够用。

AutoCompleteBehavior给我的唯一“惊喜”,也就是在一开始,让我忽然觉得,能够这么轻松地为一个文本框添加一个自动完成的能力。但是在一开始的激动过后,我也就仔细地想,这个控件真的好用么?第一个让人感到“震撼”的自动补全应用,应该就是Google Suggest了(如下图)。使用AutoCompleteBehavior能够做到这样的应用吗?


当然不行。AutoCompleteBehavior只能作出最简单的提示,其它什么功能也没有。无法设置样式,无法自定义信息,这就是我们想要的功能吗?这就是所谓的“桌面级”体验吗?很显然,这远远不够。豪不夸张地说,我是怀着对于AutoCompleteBehavior的强烈不满(其实这是前几天我在向别人介绍Atlas时被人Challenge的结果),决定自定义一个加强的AutoCompleteBehavior,不过其实唯一的增强也就是提供了用户自定义模版的能力。还好,有了Atlas的AutoCompleteBehavior作为参考,做一些扩展不难。

埋头做了几个小时,差不多完成了,也就发不出来,就当一个参考吧。

我定义了Jeffz.UI.AutoCompleteBehavior,大约一半代码与Sys.UI.AutoCompleteBehavior相同。另外在它的基础上增加了以下属性:

1、itemTemplate,Sys.UI.ITemplate,自定义每个Item的Template。
2、completionListCssClass,String,自动补全框的class。
3、itemCssClass,String,正常情况下每个Item的class。
4、highlightedItemCssClass,String,高亮的每个Item的class。
5、textProperty,String,决定补全内容的Property。

这里可能值得提一下最后一个属性textProperty。Jeffz.UI.AutoCompleteBehavior请求的Web Services方法的返回并不是保存所有文本的数组,而是一个对象数组,每一个对象有数个属性,在使用时可以将某个属性与模版中的某个控件进行了绑定。而textProperty指定的属性就是最后被用于文本框内文本的属性。

在测试时发现,如果和Atlas的其余控件一样(比如ListView),不及时销毁Template实例化之后生成的对象,内存占用量会比较大,毕竟AutoCompleteBehavior会大量生成对象。不过经过优化后的Jeffz.UI.AutoCompleteBehavior内存占用与Sys.UI.AutoCompleteBehavior相比,没有很明显的增加。

不过,Jeffz.UI.AutoCompleteBehavior还是有些不能自定义的地方,例如CompletionList的边框和宽度,如果完全使用用户定义的CssClass来设置宽度,在IE下没有任何问题的应用,在FireFox下会没有理由地慢慢变宽,这令我百思不得其解,似乎让我对于Sys.UI.AutoCompleteBehavior那么多限制有了一丝理解。因此最后,对于CompelitionList,Jeffz.UI.AutoCompleteBehavior强制使它与文本框同宽,边框为1px。别的地方似乎一时没有发现什么问题,对于不同浏览器的兼容程度也比较让人满意。

似乎说得再多,不如看两个例子,我模仿Google Suggest和Windows Live Mail的Email提示,制作了两个示例:

一、Search Suggest(模仿Google Suggest)

这个例子的样式完全模拟了Google Suggest。

首先是HTML,在这个网页中,只存在一个id为searchTextBox的文本框。代码如下:
<atlas:ScriptManager ID="ScriptManager1" runat="server" />
<input id="searchTextBox" type="text" style="width:300px;"/>

然后提供一个div作为AutoCompleteBehavior的Completion List(可选,如果不提供,AutoCompleteBehavior会自己创建一个),并且创建一个div作为提示每一项的模版。代码如下:
<div id="itemTemplate" style="padding:3px; clear:both; height:13px;">
    
<div id="lblKeyword" class="keyword" style="float:left; width:200px; overflow:hidden;"></div>
    
<div style="font-size:10px; float:right;" class="result">
        
<span id="lblResult"></span>
        
<span>&nbsp;results</span>
    
</div>
</div>

可以看到,在这里,我使用了大量内嵌的style,这不是一个好的Practice,不过我在这里是为了使用最简的方法来为模版中“不变”的样式设值。在这里可以看到,在每一项内部,有一个<div />浮动在最左,用于显示提示用自动补全的词,还有一个<div />浮动在最右,用来显示结果数量。

然后就是我们使用的Style:
<style type="text/css">
    body, input 
{ font-family:Arial; font-size:12px; }
    .completionListClass 
{ border: solid 1px #CCCCCC; cursor:default; }
    .itemClass 
{ background-color:white; }
    .itemClass .keyword 
{ color:black; }
    .itemClass .result 
{ color:green; }
    .highlightedItemClass 
{ background-color:blue; }
    .highlightedItemClass .keyword 
{ color:white; }
    .highlightedItemClass .result 
{ color:white; }
</style>

可以看到,我们使用了嵌套的CSS Class,例如,定义了模版某一项的CSS Class为itemClass,那么class被设为result的span,其color值就会被设成green。

最后就是最重要的Atlas Xml Scripts:
Atlas Xml Scripts

在这里,我们将itemTemplate的layoutElement设为itemTemplate,并将Keyword值绑定到lblKeyword的text,还有将Result的值绑定到lblResult的text上。请注意,我们将textProperty设为Keyword,表示将Keyword的值作为最后填充文本框的内容。

自然,我们还有所需要的Web Services方法,自然还包括所需的类:
GetSearchWords方法和SearchResult

和官方的例子相似,从一个文本文件中读出所有的提示信息,一行一个。在这里,我们会另外给一个随机的整数作为Result值。在获得prefixText后,我们将搜索Keyword相应的SearchResult,并且按照Result值排序后输出。我们可以想象出这里每一个数据对象的样子,也能想象出最后绑定后的结果。

既然这样,我们来看一下效果吧:


看上去还不错吧。:)



二、E-mail Suggest(模仿Windows Live Mail的E-mail提示)

在这里,我演示一下使用了Jeffz.UI.AutoCompleteBehavior,可以将自动补全变得多么的灵活。由于现在自动填充的文本,和显示在模版里的内容已经完全分离了,因此我们能将任何样式的内容显示在页面上,甚至直接是HTML。在这个例子中,我们就会直接将HTML写到模版中。我们来看一下:

首先是HTML:
<atlas:ScriptManager ID="ScriptManager1" runat="server" />
<input id="searchTextBox" type="text" style="width:300px;"/>

接着是completionList和itemTemplate:
<div id="completionList"></div>

<div id="itemTemplate" style="padding:2px;">
    
<span id="lblEncodedEmail"></span>
</div>

Style:
<style type="text/css">
    body, input 
{ font-family: Verdana; font-size: 12px; }
    .completionListClass 
{ border: solid 1px #CCCCCC; cursor: default; }
    .itemClass 
{ background-color: white; }
    .highlightedItemClass 
{ background-color: #d2eaf6; }
</style>

Atlas Xml Scripts:
Atlas Xml Scripts

和刚才的例子基本相同,只是我们在这里将EncodedEmailSuggest(HTML编码后用于显示的信息)绑定在lblEncodedEmail的text属性上时,需要将该label的htmlEncode属性设为false。这样,text属性就会被设在innerHTML上,这样就达到了我们需要的效果。另外textProperty的值为“Email”。

接下来就是我们需要的Web Services方法和所需要的EmailSuggest类:
GetEmailSuggest方法和EmailSuggest类

我们查找相关的Email(只要有任意部分字符串与prefixText相同即可),然后将EmailSuggest对象的Email属性设为该Email的原始值(作为填充文本框的内容),再将Email进行HtmlEncode后,将相关的部分使用“<b></b>”进行包裹,这样就组成了最终用来显示的HTML值。我们直接将其显示在模版中,就是我们最终需要的结果。

我们还是来看一下使用效果吧:


可能不太好看,但是效果还是达到了。


有了自定义模版的功能,剩下的只需要发挥想象力即可。现在我们的AutoCompleteBehavior更加实用了:)



点击这里下载Jeffz.UI.AutoCompleteBehavior源文件以及示例源文件。
点击这里查看Search Suggest使用效果。
点击这里查看E-mail Suggest使用效果。

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

24 条回复

  1. 老赵
    admin
    链接

    老赵 2006-10-20 03:11:00

    太晚了,所以这篇文章写得就马虎了些,由于写了这个控件,所以可能“深入Atlas系列”会停一天……
    还有发现最近博客园的文件下载总是会下载成为一个无效的zip文件,如果有朋友需要源文件的话就在这里留下您的E-mail吧,我可以发给您。

  2. anikin[未注册用户]
    *.*.*.*
    链接

    anikin[未注册用户] 2006-10-20 07:59:00

    非常不错,太感谢了

  3. TerryLee
    *.*.*.*
    链接

    TerryLee 2006-10-20 08:38:00

    cool!

  4. 老刘.
    *.*.*.*
    链接

    老刘. 2006-10-20 08:50:00

    well done, really really well done!

  5. 阿瑞
    *.*.*.*
    链接

    阿瑞 2006-10-20 09:04:00

    支持一下

  6. 出走的影子
    *.*.*.*
    链接

    出走的影子 2006-10-20 09:34:00

  7. 阿不
    *.*.*.*
    链接

    阿不 2006-10-20 10:07:00

    真的很不错

  8. 老赵
    admin
    链接

    老赵 2006-10-20 10:11:00

    @出走的影子
    等有时间了再考虑吧,现在研究研究再写写文章已经基本上没有空闲时间了。:)

  9. 老赵
    admin
    链接

    老赵 2006-10-20 10:12:00

    @anikin
    @TerryLee
    @老刘.
    @阿瑞
    @阿不
    谢谢支持:)

  10. TerryLee
    *.*.*.*
    链接

    TerryLee 2006-10-20 11:57:00

    @Jeffrey Zhao
    如果在这基础上加以扩展,再能够提供多单词建议就更好了:-)

    http://www.codeproject.com/Ajax/CustomAutoCompleteExt.asp

  11. 老赵
    admin
    链接

    老赵 2006-10-20 12:05:00

    @TerryLee
    呵呵,这个不难的。
    其实做得好的话,我想过,还需要作点别的扩展比如各种事件之类的。
    我现在的扩展基本上只是在AutoCompleteBehavior的基础上作一点修改,否则样式太单调了……

  12. 小蜗牛
    *.*.*.*
    链接

    小蜗牛 2006-10-20 17:14:00

    真好。。。:'(

  13. 老赵
    admin
    链接

    老赵 2006-10-20 17:26:00

    @出走的影子
    而且需要寄信到美国,太麻烦了……

  14. wsxcy[未注册用户]
    *.*.*.*
    链接

    wsxcy[未注册用户] 2006-10-21 16:29:00

    I 服了 You
    给俺一份:wsxcy@126.com

  15. 老赵
    admin
    链接

    老赵 2006-10-21 17:20:00

    @wsxcy
    多谢支持。

    只是Atlas已经更新得面目全非了,我的扩展已经无法使用了。如果您有兴趣就随便看看吧……:(

  16. Tseng
    *.*.*.*
    链接

    Tseng 2006-10-22 00:28:00

    AJAX Control Toolkit 里面的PopupControl就是这样的功能.

  17. 老赵
    admin
    链接

    老赵 2006-10-22 00:32:00

    @Tseng
    功能是不一样的。:)

  18. Tseng
    *.*.*.*
    链接

    Tseng 2006-10-22 00:39:00

    @Jeffrey Zhao
    刚才又去官方网站看了一下PopupControl,发现如果网速不行的话,选择某个日期之后窗口很久才能关闭. 我觉得这个动作不需要Postback了吧.

  19. Tseng
    *.*.*.*
    链接

    Tseng 2006-10-22 00:40:00

    讨论AutoCompleteBehavior,变成讨论PopupControl了,:)

  20. 老赵
    admin
    链接

    老赵 2006-10-22 01:02:00

    @Tseng
    在PopupControl的例子中应该使用了UpdatePanel。Calendar控件的显示,Click事件的响应都是在后台PostBack后反馈到页面上的。当然,这只是个例子,实际使用还是应该尽量减少PostBack次数。
    //讨论什么都可以。:)

  21. 软件之美,美在缺陷-蒋勇星
    *.*.*.*
    链接

    软件之美,美在缺陷-蒋勇星 2007-03-14 00:14:00

    感谢!
    在Ajax ToolKit团队于3月1日Release的版本中,我们发现AutoCompleteExtender控件提供了对OnSelected事件的支持,可是我仍然没有找到这个事件和响应这个事件的方法。
    请指教!

  22. 老赵
    admin
    链接

    老赵 2007-03-14 00:36:00

    @软件之美,美在缺陷-蒋勇星
    有时间的话,我帮您看一下。:)

  23. 软件之美,美在缺陷-蒋勇星
    *.*.*.*
    链接

    软件之美,美在缺陷-蒋勇星 2007-03-14 00:43:00

    @Jeffrey Zhao
    另外,我注意到你告诉@IVW说这篇文章已经过期,是否有新的方法来实现这里面新增的特性?最新的ToolKit里AutoCompleteBehavior仍然没有能够出现多行结果的能力。

  24. 老赵
    admin
    链接

    老赵 2007-03-14 00:48:00

    @软件之美,美在缺陷-蒋勇星
    有机会的话我肯定要重新再写一个的,呵呵

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我