【功能概述】Accordion可以让你设计多个panel 并且一次只显示一个Panel .在页面上的显示效果就像是使用了多个CollapsiblePanels只不过每一次只展开其中一个CollapsiblePanel.Accordion控件内部包含了若干个AccordionPane,每一个AccordionPane的template里包括了对其Header和Content的定义。我们可以在后台代码中通过SelectedIndex属性取得当前展开的哪一个Panel,还可以控制哪一个Panel展开。
经常可以见到类似的效果,比如QQ、Msn好友分类的折叠效果。
【细节】
(1)不要把Accordion放在Table中而又把 FadeTransitions 设置为True,这将引起布局混乱
(2) 在AccordionPane模板中的Content中可以定义任何Web元素,表现的就像一个容器
(3) AccordionPane内容模板自动改变大小有三种AutoSize modes :None(推荐) Limit Fill
(4) $find('ctl00_ContentPlaceHolder1_MyAccordion_AccordionExtender')这里找到的是Behavior.什么是Behavior呢?在Asp.net Ajax框架中包含一组动作并完成一个功能. Accordion的一个Behavior就是淡入淡出.
找到Behavior的引用,behavior.set_FadeTransitions() behavior.get_FadeTransitions()的方式来实现具体某一个Behavior的访问和修改.
var behavior = $find('ctl00_SampleContent_MyAccordion_AccordionExtender');这种写法是不好的,我们在自动测试的页面中发现了更好的写法: var behavior=$find("<%= MyAccordion.ClientID %>_AccordionExtender");
【代码示意】
ContentCssClass="accordionContent" FadeTransitions="false" FramesPerSecond="40"
TransitionDuration="250" AutoSize="None">
1. Accordion
2. AlwaysVisibleControl
【功能概述】
AlwaysVisibleControl 是一个简单的扩展控件可以让一部分内容浮动在页面上,当滚动页面或者改变浏览器大小时总是可见的。它可以扩展任意一个Asp.net 控件,并可按照要求设置水平 竖直方向上的相对距离.
最多的应用是在线阅读的目录和不胜其烦的浮动小广告。
【细节】
(1) 避免控件闪烁,要扩展的控件要使用absolutely position
(2) HorizontalSide="Center" VerticalSide="Top" 使用这个方式控制浮动的位置
(3) Var label = ocument.getElementById('ctl00_SampleContent_currentTime');这行代 码我们可以使用更简单的方法:var label = $get('ctl00_SampleContent_currentTime');
【代码示意】
3. Animation
【功能概述】
28个控件种效果最酷的!顾名思义实现动画效果。它是一个插入式,可扩展的框架可以方便的为你的页面添加动画效果。
【细节】
请参考页面代码阅读下面的细节内容:
(1)Sys.UI.DomElement.getLocation(b) 取得控件位置的函数,常用!!!
(2)动画分为两种:Animation Action 后者的强大让我很兴奋
(3)
(4)
(5)【Action】
(6)【Action】
(7)【Action】
(8) 【Action】
(9) 【Action】
(10)【Animation】
(11)【Animation】
(12) 【Animation】
(13)【Animation】
(14) 【Animation】
(15)动画效果是在用户某一个动作发生的时候触发,触发的时机包括:OnLoad OnClick OnMouseOver OnMouseOut OnHoverOver OnHoverOut
正式版的页面文件为动画脚本添加了注释更加清晰易懂.上面列出的是常用的一些动画效果,全部资料参见Anmation Reference。
仔细阅读Animation的页面代码,其实我们已经提前触摸到了Xaml的编程风格。Asp.net Ajax之后的下一代WEB界面是WPF/E,WPF/E现在支持的是”javascript+Xaml” 还不支持”C# + Xaml”。
下一代的WEB UI会是怎样的?下一个版本的Asp.net 会怎样安排Ajax的位置?WPF/E会不会被整合在新版本的Asp.net中呢?期待中……
【示意代码】
代码示意:
runat="server" TargetControlID="ctrl">
4. AutoComplete NEW!!!
【功能概述】
AutoComplete控件是对Asp.net文本框控件的扩展,当用户词汇前面的字母时以弹出区域的形式给出备选词。这个功能的完成依赖于特定的Web Service。
在正式版的Ajax Control Toolkit中看到自动完成扩展控件有一种感觉:它终于出现在了它应该出现的地方。之前AutoComplete控件是在CTP版本中以核心组件的形式出现的,这个功能极为明确的控件被归类到核心组件,我还是比较迷惑。正式版中它终于成为了一个扩展控件。
Google的自动完成功能,新浪 网易等信箱的收件人自动完成功能是这个功能的成功应用。
【细节】
从Atlas的版本开始,AutoComplete的使用方法就没有太大的改变,只要注意:
(1)调用的Web Service方法签名有要求:
[WebMethod]
public string[] GetCompletionList(string prefixText, int count) { ... }
(2)MinimumPrefixLength最短前缀字符数,就是说你至少要键入几个字符才会出现提示
5. Calendar NEW!!!
【功能概述】
Calendar同样是对文本框的扩展,当点击文本框的时候弹出日期选择选项。现在的版本提供的功能已经和WinForm中的日期控件一样,可以通过点击日期选择,点击箭头在年月之间切换。
【细节】
(1)同样是对文本框的扩展,文本框获得焦点就会出现日期选择,样式是可以自定义的
(2)虽然一定是对文本框的扩展但是我们还是可以指定弹出按钮PopupButtonID,一旦这个值设定了,文本框获得焦点也不会弹出日期选择
(3)不需要把它放在UpdatePanel中
6. CascadingDropDown
【功能概述】
CascadingDropDown 控件是对ASP.NET DropDownList control的扩展,实现对一个DropDownList操作时其它DropDownList发生相应的变化。这个功能的实现依赖于Web Service。
【细节】
(1)如果使用Web service 方法签名必须符合下面的形式:
[WebMethod]
public CascadingDropDownNameValue[] GetDropDownContents(
string knownCategoryValues, string category){...}
(2)在阅读代码的时候请关注:Category属性。官方说法The name of the category this DropDownList represents 实打开~/App_Data/CarsService.xml你就发现这是Xml的元素标签。从这个角度我们就解决了为什么联动,即联动的本质;同时也明白了调用Service的参数约定。
【示意代码】
另外页面上还有一段定义UpdatePanel的代码很典型,可以作为参考:
7. CollapsiblePanel
【功能概述】
这个控件几乎在每一个页面上都出现了。它是非常灵活的一个控件,可以扩展任何ASP.NET Panel control。在页面上轻松实现展开收缩效果。这种效果我们最熟悉的恐怕就是XP的文件任务栏了。
【细节】
(1) CollapsiblePanel 默认认为使用了 标准 CSS box model 早期的浏览器要!DOCTYPE 中设置页面为自适应方式提交数据rendered in IE's standards-compliant mode.
(2) 可以自动展开 自动收缩Autoexpand="true" AutoCollapse="true"但是这两个本身是互斥的不能同时为True;如果设置了这两个属性其中一个为True就不要在设置 Collapsed="True",这样就没有意义了。
(3) TextLabelID="Label1"这个属性有什么深意\高级的操作么?我还在研究。。。
代码示意:
TargetControlID="Panel1"
CollapsedSize="0"
ExpandedSize="300"
Collapsed="True"
ExpandControlID="LinkButton1"
CollapseControlID="LinkButton1"
AutoCollapse="False"
AutoExpand="False"
ScrollContents="True"
TextLabelID="Label1"
CollapsedText="Show Details "
OpenedText="Hide Details"
ImageControlID="Image1"
ExpandedImage="~/images/collapse.jpg"
CollapsedImage="~/images/expand.jpg"
ExpandDirection="Height"/>
8. ConfirmButton
【功能概述】
这个控件是对Button和继承了Button的控件的扩展,它可以捕捉到用户点击了对话框中的“是”“否”;如果是“是”就继续执行后面的代码,反之就停止执行它默认的提交行为。
【细节】
(1) 要扩展的LinkButton Button 以及ConfirmButtonExtender都要放在updatepanel里面
如果是放在外面,点击“确定”或者“取消”之后还是会导致页面刷新!
(2)更简单的方法:
this.Button1.Attributes["onclick"]="javascript:return confirm('确定要停止下载么?');";
(3) 如果是需要服务器端获取用户选择,还是使用模式弹出吧
9.DragPanel
【功能概述】
DragPanel extender可以轻松的让控件 "draggability".DragPanel 扩展的目标是任意 ASP.NET Panel .你可以设置拖动行为的细节,比如哪里是类似于标题栏一样的区域。
【细节】
(1) TargetControlID 要拖动的控件
(2) DragHandleID 拖动的标题栏所在的ControlID 示例代码中: panel6包含panel7(标题) panel8(内容)扩展的对象是panel6
(3) 是不是发现这段JS代码了呢?如果去掉这段代码,图到页面边缘的时候是不正常的,它自己跑回原来位置了

【示意代码】
代码示意
TargetControlID="Panel3"
DragHandleID="Panel4" />
10. DropDown
【功能概述】
DropDown 同样是一个 ASP.NET AJAX extender 可以对任何 ASP.NET control 进行扩展实现 SharePoint-style drop-down menu效果。弹出的只不过是其它的panel或者控件而已。 在IE浏览器中下拉列表总是在最前面的,的确是影响页面效果,这个控件的出现可以解决这一问题.这随时随地的弹出窗口成为WEB 2.0网站的标志性建筑,弹出的东西也越来越丰富。
【细节】
(1)TargetControlID要在什么控件上实现扩展
(2)DropDownControlID弹出来什么
(3) 示例中是对一个Label进行的扩展,我试着扩展TextBox效果更好!
【示意代码】
代码示意:
DropDownControlID="DropPanel" />
还有一段代码有很多可以学习的地方:
代码示意:
11. DropShadow
【功能概述】
阴影效果
【 细节】
(1) Width 单位:px 默认5px
(2) Opacity 不透明度0-1.0 默认.5
【示意代码】
代码示意:
TargetControlID="Panel1"
Opacity=".8"
Rounded="true"
TrackPosition="true" />
12. DynamicPopulate
【功能概述】
能实用Web Service或页面方法来动态的替换控件的内容。调用的方法返回的是一个Html的字符串,作为目标元素的子节点插入其中。
【 细节】
(1)ClearContentsDuringUpdate 替换之前先清除以前的内容(默认True)
(2)PopulateTriggerControlID 触发器绑定的控件 单击时触发
(3)ContextKey传递给Web Service的随机字符串
(4) Web Service方法签名必须符合下面的形式:
[WebMethod]
string DynamicPopulateMethod(string contextKey)
{...}
Note you can replace "DynamicPopulateMethod" with a naming of your choice, but the return
type and parameter name and type must exactly match, including case.
(5) 我们非常欣慰的一点就是BehaviorID="dp1",这种用法是我所期望的。
(6) CustomScript 怎么用呢??This script must evaluate to a string value. ??
【示意代码】
代码示意:
TargetControlID="Panel1"
ClearContentsDuringUpdate="true"
PopulateTriggerControlID="Label1"
ServiceMethod="GetHtml"
UpdatingCssClass="dynamicPopulate_Updating" />
代码示意2:
ClearContentsDuringUpdate="true"
PopulateTriggerControlID="Label1"
TargetControlID="Panel1"
ServiceMethod="GetHtml"
UpdatingCssClass="dynamicPopulate_Updating">
13. FilteredTextBox
【功能概述】
FilteredTextBox扩展控件用来阻止用户在文本框输入无效字符 。由于这种效果的实现是依赖于deactivating JavaScript(怎么翻译呢?),所以不要期望数据会发送到服务器端进行校验。
【细节】
(1)过滤条件Numbers LowercaseLetters UppercaseLetters Custom
(2)过滤条件也可以是Custom的组合 FilterType="Custom, Numbers"
(3)ValidChars="+-=/*()." Custom要定义这样的有效字符串
(4)这个控件我认为是聊胜于无,我们要把允许输入的数据进行枚举,太难了。事实上,这个控件在任何状态下都是接受中文的。如果使用正则表达式情形或许好些。看它的实现代码还有进一步改进的可能,学习研究中……
【示意代码】
示意代码:
TargetControlID="TextBox3"
FilterType="Custom, Numbers"
ValidChars="+-=/*()." />
在该控件的实现代码中我发现了这样一段,这可能是一个突破口:
特殊键排除代码:
< var scanCode;
if (evt.rawEvent.keyIdentifier) {
// Safari
// Note (Garbin): used the underlying rawEvent insted of the DomEvent instance.
if (evt.rawEvent.ctrlKey || evt.rawEvent.altKey || evt.rawEvent.metaKey) {
return;
}
if (evt.rawEvent.keyIdentifier.substring(0,2) != "U+") {
return;
}
scanCode = evt.rawEvent.charCode;
if (scanCode == 63272 /* Delete */) {
return;
}
}
else {
scanCode = evt.charCode;
}
if (scanCode && scanCode >= 0x20 /* space */) {
var c = String.fromCharCode(scanCode);
if(!this._processKey(c)) {
evt.preventDefault();
}
}
}
14. HoverMenu
【功能概述】
HoverMenu控件可以扩展任何 ASP.NET WebControl, 同时将把附加的显示内容关联到该控件上,当用户移动鼠标到该控件的时候附加的内容将显示出来。
【细节】
(1) PopupControlID要弹出来什么
(2)PopupPostion 在哪里弹出来Left (Default), Right, Top, Bottom, Center.
(3)OffsetX/OffsetY 弹出项与源控件的距离
(4) PopDelay 弹出延时显示 单位milliseconds. Default is 100.
【代码示意】
代码示意:
TargetControlID="Panel9"
HoverCssClass="popupHover"
PopupControlID="PopupMenu"
PopupPosition="Left"
OffsetX="0"
OffsetY="0"
PopDelay="50" />
示例页面上还有一个小细节:
HttpUtility.HtmlEncode()使用 HttpUtility.HtmlEncode 将危险的符号转换为它们的 HTML 表示形式。
代码示意:
15. MaskedEdit NEW!!!
【功能概述】
MaskedEdit 控件是对TextBox control的扩展.用户输入会在客户端进行验证。在示例页面中,我感觉实际效果并不是太好所以没有深入学习,不多说了。
16. ModalPopup
【功能概述】
ModalPopup 扩展控件允许在页面上模式弹出内容并阻止用户和页面上其他区域的交互。模式弹出区域的样式都是可以自定义的。 用户可以在模式弹出框选择OK/Cancel,对用户选择的处理方式有两种:使用客户端脚本或者PostBack到服务器端。这样我们就得到了用户的选择结果!
【细节】
(1) 看下面的代码可以看到执行客户端脚本的方法。
(2) 应该说这个控件是提供了一个模式弹出对话框的模板
(3) 在正式版以前的所有版本,这个控件在Opear浏览器中都是不正常的。正式版已经修正这个BUG,现在正在比较学习两个版本的源代码,看看问题的原因和解决方法是什么。
【示意代码】
代码示意:
PopupControlID="Panel2" BackgroundCssClass="modalBackground" DropShadow="true"
OkControlID="Button1" OnOkScript="onOk()" CancelControlID="CancelButton" />
17. MutuallyExclusiveCheckBox
【功能概述】
互斥复选框就像RadioButton一样,应用的场景是:“a number of choices are available but only one can be chosen”
【细节】
(1)Key属性用来分组就像RdiolistGroup一样
(2)argetControlID用来绑定已有的CheckBox
【代码示意】
ID="MustHaveGuestBedroomCheckBoxEx"
TargetControlID="MustHaveGuestBedroomCheckBox"
Key="GuestBedroomCheckBoxes" />
18. NoBot
【功能概述】
提供了简单的Captcha 图灵测试 用来屏蔽bot/spam 垃圾信息。是一个反垃圾信息控件。我查了一下资料,我的理解是:比如你点击一个按钮需要一秒钟的时间,而这一秒钟的时间你不可能再做其他的操作比如再点一次;这样区分出了人和机器。避免机器人自动点击 注册 暴力破解之类的事情
【 细节】
(1)OnGenerateChallengeAndResponse 这个属性是EventHandler
例如: protected void CustomChallengeResponse(object sender, NoBotEventArgs e) {……}
【示意代码】
代码示意:
ID="NoBot2"
runat="server"
OnGenerateChallengeAndResponse="CustomChallengeResponse"
ResponseMinimumDelaySeconds="2"
CutoffWindowSeconds="60"
CutoffMaximumInstances="5" />
NoBot控件拒绝垃圾发布程序
本文来自我即将出版的《ASP.NET AJAX程序设计 第I卷 服务器端ASP.NET AJAX Extensions与ASP.NET AJAX Control Toolkit(暂定名)》第10章第1节。请各位朋友不吝给出建议和意见。
10.1 NoBot:拒绝机器人程序
NoBot 控件可以为页面中的表单提供类似CAPTCHA[注释1]而却无需任何用户操作的验证,以阻止机器人程序自动提交垃圾信息。
10.1.1 应用场景
网 络上的垃圾信息似乎无处不在,从前是垃圾邮件、广告等。而现在,这些无孔不入的垃圾信息发布者又盯上了互联网上的各大网站。各种机器人程序(Bot)应运 而生,它们可以自动在网络上爬行并寻找带有评论或留言功能的页面,随即自动填写表单并提交,其提交垃圾信息的数量和质量更是让传统的手工发布者自愧不如。管理者往往一夜之间发现自己的网站下已经多了成千上万条广告,不但让真正有用的信息淹没于其中,更是让网站在性能上不堪重负。
由此,很 多解决方法同样应运而生,其中最著名的当属各种验证图片了。这种验证图片中的文字由计算机随机生成,并尽其所能地对其进行扭曲、变形、修饰、模糊,最终要达到的目的是只有聪明的人类才能够分析出其中的内容(如图10-1所示),而当前水平的计算机却只能够望“图”兴叹。然后将用户对这幅图片的识别文本随表 单一起发送至服务器。这样,服务器即可通过检查客户端输入的识别文字的正确与否来判断这是否是人类所为,也就达到了区分机器人程序和人类的目的。
图10-1 极其复杂的验证图片
目 前为止,这种做法非常有效,因为计算机图像处理能力的发展还不足以完全正确地识别出如此复杂的图片中的文字。不过这样做的缺点也很明显——麻烦!每次提交 一次表单都需要用户仔细睁大双眼分辨验证图象中的内容,并且输入一串毫无意义、没有任何连贯性的字符,真的是一种痛苦!而且,对于视力不便的残障人士来说,这种验证图片更是将其拒之门外。
于是,某些网站提供了另外一种可选项,即对于视力不便的残障人士,可以选择听一段朗读,并输入其中读过的字母,通过声音的方式来分辨人类和计算机,例如Hotmail的注册页面,如图10-2所示。
图10-2 以识别声音的方式来分辨人类和计算机
这样似乎考虑得很周全了……不过,如果某个用户不懂得英文,那岂不还是不能使用么?世界上有这么多种语言,难道要提供每种语言的版本?而且,即使提供了所有语言的版本,对于麻烦这个致命的问题,也仍旧是无法解决啊!
有没有一种无需用户操作的,对用户完全透明的验证机器人程序的解决方法呢?ASP.NET AJAX Control Toolkit中提供的NoBot控件即提供了这样一种相对来说比较折衷的解决方案。
10.1.2 声明语法以及常用属性
NoBot控件可以通过如下四种方式较为准确地判断出进行当前操作的是否为人类:
1. 让 客户端浏览器执行一段JavaScript,并判断其执行结果。机器人程序一般只是取得HTTP流的内容,对其分析并填写其中表单之后即提交,这个过程中 并不包含对浏览器功能的使用,也就更不会解析并运行页面中的JavaScript得到正确的运行结果。且这段JavaScript既可以是一段简单的纯数 学运算,例如123*4455=?,也可以是一些非常复杂的DOM操作,例如动态创建一个
,并返回它的位置等。这样即强迫该程序只 能够在浏览器中使用,大多数机器人程序显然对此等计算无力回天。
2. 判断客户端是否保存了本次会话状态。一般来讲,只有浏览器才会对会话状态进行关注并保存,而简单的机器人程序则会完全忽略会话状态信息。
3. 判断客户端从开始接受页面到提交表单的时间间隔。机器人程序都比较讲究“效率”,加上计算机的强大运算能力,几乎可以在接收到页面之后的瞬间就完成表单的填写并提交回服务器。而对于人类,显然不可能在如此短暂的几秒钟时间之内就完成这样复杂的一张表单。
4. 判断某段时间之内某个客户端的提交次数。同样,对于人类来说,没有能力也没有意义在比如一分钟之内填写同样的表单100次,而对于机器人程序,则这很有可能是它们的一贯作风。
以上的四种方法,虽不能百分之百地完全阻止机器人程序,然而在大多数情况下还是非常有效且相当精确的。且使用这种方法最大的优势就在于它省去了对用户交互的需要,让程序更加友好易用。
NoBot控件在页面中是完全不可见的,这似乎和我们潜意识中Ajax程序的那些眩目的界面效果没什么关系。不过从增强用户体验的角度来看,NoBot却的确是一大进步,它也正符合了Ajax的最根本设计目标——提高用户体验。
声明NoBot控件的语法将类似如下所示:
ID="noBot"
runat="server"
ResponseMinimumDelaySeconds="2"
CutoffWindowSeconds="60"
CutoffMaximumInstances="5"
OnGenerateChallengeAndResponse="noBot_GenerateChallengeAndResponse" />
NoBot控件继承于System.Web.UI.WebControls.CompositeControl,并间接继承于 System.Web.UI.WebControls.WebControl,也就拥有了这些控件的所有属性/方法/事件,声明NoBot控件时所常用的属性标签如表10-1所示。
表10-1 声明NoBot控件时的常用属性标签[注释2]
1. ResponseMinimumDelaySeconds: 一个合理的客户端从开始接受页面到提交表单的时间间隔,单位为秒。在该时间段之内的提交将被认为是机器人所为。
2. CutoffWindowSeconds:指定一个统计同一客户端提交次数的窗口时间段,单位为秒。在该时间段之内的提交次数超过CutoffMaximumInstances所指定的值将被认为是机器人所为。
3. CutoffMaximumInstances:指定在窗口时间段内同一客户端最多的提交次数。在CutoffWindowSeconds所指定的时间段之内的提交次数超过该值将被认为是机器人所为。
4. OnGenerateChallengeAndResponse:指定GenerateChallengeAndResponse事件的处理函数。在该事件处理函数中我们可以设定强制浏览器执行的一段JavaScript以及其预期的执行结果。若浏览器的执行结果和预期结果不符,则本次提交将被认为是机器人所为。
10.1.3 示例程序:阻止机器人程序的提交
NoBot控件虽然设置起来比较简单,但对其进行合理的配置却并不容易,检查标准太高或太低均难以达到我们的预期目标。接下来让我们通过一个示例程序来分析讨论该控件的使用方法。
首先在新建的页面中添加ScriptManager控件,然后添加一个TextBox和一个Button,用来模拟出一个最简单的输入表单,再加入一个Label,用来显示机器人程序检测是否通过的信息:
接下来是NoBot控件的声明:
ResponseMinimumDelaySeconds="2"
OnGenerateChallengeAndResponse="noBot_GenerateChallengeAndResponse"
runat="server" />
我们先来看ResponseMinimumDelaySeconds属性,在该示例程序中,因为表单非常简单,只有一个域,我们将其设置为较短的2 (秒)。在实际开发中,我们应该根据表单的复杂程度估计用户填写需要的时间,并相应地配置该属性。例如,对于如Hotmail中复杂的用户注册表单来讲, 将该属性值设置为100秒都不足为过——在100秒之内能够将该注册页面填写完成的,除了机器人程序也只有天才了。
对于CutoffWindowSeconds属性,这里我们设置为10(秒)。该属性值越大,则统计的时间段也就越长,判断结果也就愈加有信服力,但同时这样也会造成服务器端更大的开销。一般情况下,将该属性设置为10-100是一个比较合理的选择。
对于CutoffMaximumInstances属性,这里我们设置为2(次),配合CutoffWindowSeconds属性,其含 义即为在10秒钟之内同一个客户端最多可以提交2次,超过该次数的提交均被认为是机器人程序。在考虑设置该属性时,我们也要考虑表单的复杂程度并相应地估 计用户填写所需要的时间。
而对于OnGenerateChallengeAndResponse属性,即 GenerateChallengeAndResponse事件的处理函数,我们将在其中设定强制浏览器执行的JavaScript以及预期的结果,这里将其指定为noBot_GenerateChallengeAndResponse(),函数的名称无关紧要,让开发人员能够理解就好。该事件处理函数的签名如下:
protected void noBot_GenerateChallengeAndResponse(object sender, NoBotEventArgs e)
注意其中的类型为NoBotEventArgs的参数e,将在稍后用到。在该函数中,我们将动态生成一个随机大小的
2. 判断客户端是否保存了本次会话状态。一般来讲,只有浏览器才会对会话状态进行关注并保存,而简单的机器人程序则会完全忽略会话状态信息。
3. 判断客户端从开始接受页面到提交表单的时间间隔。机器人程序都比较讲究“效率”,加上计算机的强大运算能力,几乎可以在接收到页面之后的瞬间就完成表单的填写并提交回服务器。而对于人类,显然不可能在如此短暂的几秒钟时间之内就完成这样复杂的一张表单。
4. 判断某段时间之内某个客户端的提交次数。同样,对于人类来说,没有能力也没有意义在比如一分钟之内填写同样的表单100次,而对于机器人程序,则这很有可能是它们的一贯作风。
以上的四种方法,虽不能百分之百地完全阻止机器人程序,然而在大多数情况下还是非常有效且相当精确的。且使用这种方法最大的优势就在于它省去了对用户交互的需要,让程序更加友好易用。
NoBot控件在页面中是完全不可见的,这似乎和我们潜意识中Ajax程序的那些眩目的界面效果没什么关系。不过从增强用户体验的角度来看,NoBot却的确是一大进步,它也正符合了Ajax的最根本设计目标——提高用户体验。
声明NoBot控件的语法将类似如下所示:
ID="noBot"
runat="server"
ResponseMinimumDelaySeconds="2"
CutoffWindowSeconds="60"
CutoffMaximumInstances="5"
OnGenerateChallengeAndResponse="noBot_GenerateChallengeAndResponse" />
NoBot控件继承于System.Web.UI.WebControls.CompositeControl,并间接继承于 System.Web.UI.WebControls.WebControl,也就拥有了这些控件的所有属性/方法/事件,声明NoBot控件时所常用的属性标签如表10-1所示。
表10-1 声明NoBot控件时的常用属性标签[注释2]
1. ResponseMinimumDelaySeconds: 一个合理的客户端从开始接受页面到提交表单的时间间隔,单位为秒。在该时间段之内的提交将被认为是机器人所为。
2. CutoffWindowSeconds:指定一个统计同一客户端提交次数的窗口时间段,单位为秒。在该时间段之内的提交次数超过CutoffMaximumInstances所指定的值将被认为是机器人所为。
3. CutoffMaximumInstances:指定在窗口时间段内同一客户端最多的提交次数。在CutoffWindowSeconds所指定的时间段之内的提交次数超过该值将被认为是机器人所为。
4. OnGenerateChallengeAndResponse:指定GenerateChallengeAndResponse事件的处理函数。在该事件处理函数中我们可以设定强制浏览器执行的一段JavaScript以及其预期的执行结果。若浏览器的执行结果和预期结果不符,则本次提交将被认为是机器人所为。
10.1.3 示例程序:阻止机器人程序的提交
NoBot控件虽然设置起来比较简单,但对其进行合理的配置却并不容易,检查标准太高或太低均难以达到我们的预期目标。接下来让我们通过一个示例程序来分析讨论该控件的使用方法。
首先在新建的页面中添加ScriptManager控件,然后添加一个TextBox和一个Button,用来模拟出一个最简单的输入表单,再加入一个Label,用来显示机器人程序检测是否通过的信息:
接下来是NoBot控件的声明:
ResponseMinimumDelaySeconds="2"
OnGenerateChallengeAndResponse="noBot_GenerateChallengeAndResponse"
runat="server" />
我们先来看ResponseMinimumDelaySeconds属性,在该示例程序中,因为表单非常简单,只有一个域,我们将其设置为较短的2 (秒)。在实际开发中,我们应该根据表单的复杂程度估计用户填写需要的时间,并相应地配置该属性。例如,对于如Hotmail中复杂的用户注册表单来讲, 将该属性值设置为100秒都不足为过——在100秒之内能够将该注册页面填写完成的,除了机器人程序也只有天才了。
对于CutoffWindowSeconds属性,这里我们设置为10(秒)。该属性值越大,则统计的时间段也就越长,判断结果也就愈加有信服力,但同时这样也会造成服务器端更大的开销。一般情况下,将该属性设置为10-100是一个比较合理的选择。
对于CutoffMaximumInstances属性,这里我们设置为2(次),配合CutoffWindowSeconds属性,其含 义即为在10秒钟之内同一个客户端最多可以提交2次,超过该次数的提交均被认为是机器人程序。在考虑设置该属性时,我们也要考虑表单的复杂程度并相应地估 计用户填写所需要的时间。
而对于OnGenerateChallengeAndResponse属性,即 GenerateChallengeAndResponse事件的处理函数,我们将在其中设定强制浏览器执行的JavaScript以及预期的结果,这里将其指定为noBot_GenerateChallengeAndResponse(),函数的名称无关紧要,让开发人员能够理解就好。该事件处理函数的签名如下:
protected void noBot_GenerateChallengeAndResponse(object sender, NoBotEventArgs e)
注意其中的类型为NoBotEventArgs的参数e,将在稍后用到。在该函数中,我们将动态生成一个随机大小的
并添加到 页面的DOM树中,且将该
的长宽乘积作为预期值保存起来。同时将向页面中写入一段JavaScript,该JavaScript用 来在客户端运行时找到该
并取得其长宽的乘积。这样在页面回送之后,NoBot控件就可以通过比较预期值与从客户端得到的实际值是否 相等来判断客户端是否为真正的浏览器,进而判断客户端是否为机器人。
在noBot_GenerateChallengeAndResponse()方法中,首先新建一个ASP.NET Panel,选择Panel是因为该控件将被呈现为HTML
在noBot_GenerateChallengeAndResponse()方法中,首先新建一个ASP.NET Panel,选择Panel是因为该控件将被呈现为HTML
元素,方便得到其长宽属性:
Panel noBotPanel = new Panel();
接下来,生成两个随机数,将分别设置到该Panel的长和宽属性上:
Random rand = new Random();
int width = rand.Next(80);
int height = rand.Next(120);
随后,为这个Panel指定一个随机的ID,指定ID是为了让之后的JavaScript中可以在客户端取到其生成的
Panel noBotPanel = new Panel();
接下来,生成两个随机数,将分别设置到该Panel的长和宽属性上:
Random rand = new Random();
int width = rand.Next(80);
int height = rand.Next(120);
随后,为这个Panel指定一个随机的ID,指定ID是为了让之后的JavaScript中可以在客户端取到其生成的
,而选用随机的ID是为了让程序更加具有不确定性,进一步迷惑机器人程序:
noBotPanel.ID = string.Format("noBotPanel{0}", rand.Next(1000));
然后将上面生成的长、宽应用到该Panel上:
noBotPanel.Width = width;
noBotPanel.Height = height;
为了不干扰页面的现有布局,我们还要设置一下该Panel的样式,将其隐藏起来:
noBotPanel.Style.Add(HtmlTextWriterStyle.Visibility, "hidden");
noBotPanel.Style.Add(HtmlTextWriterStyle.Position, "absolute");
注意第一句实际上是设置了visibility: hidden;,而并没有选择我们常用的display: none;。因为若选用后者,则浏览器将认为其大小为0。
然后将该Panel添加为NoBot的子控件,同样是为了避免可能出现的对页面结构的影响:
(sender as NoBot).Controls.Add(noBotPanel);
然后设置将在浏览器中执行的这一段检验的JavaScript:
e.ChallengeScript = string.Format("var noBotPanel = document.getElementById('{0}'); noBotPanel.offsetWidth * noBotPanel.offsetHeight;", noBotPanel.ClientID);
注意到这段JavaScript在运行时将首先通过该Panel的客户端ID得到其实际
noBotPanel.ID = string.Format("noBotPanel{0}", rand.Next(1000));
然后将上面生成的长、宽应用到该Panel上:
noBotPanel.Width = width;
noBotPanel.Height = height;
为了不干扰页面的现有布局,我们还要设置一下该Panel的样式,将其隐藏起来:
noBotPanel.Style.Add(HtmlTextWriterStyle.Visibility, "hidden");
noBotPanel.Style.Add(HtmlTextWriterStyle.Position, "absolute");
注意第一句实际上是设置了visibility: hidden;,而并没有选择我们常用的display: none;。因为若选用后者,则浏览器将认为其大小为0。
然后将该Panel添加为NoBot的子控件,同样是为了避免可能出现的对页面结构的影响:
(sender as NoBot).Controls.Add(noBotPanel);
然后设置将在浏览器中执行的这一段检验的JavaScript:
e.ChallengeScript = string.Format("var noBotPanel = document.getElementById('{0}'); noBotPanel.offsetWidth * noBotPanel.offsetHeight;", noBotPanel.ClientID);
注意到这段JavaScript在运行时将首先通过该Panel的客户端ID得到其实际
元素的引用,然后使用 offsetWidth和offsetHeight得到其实际大小,并将其乘积返回。这段JavaScript赋值给了 e.ChallengeScript,即NoBotEventArgs类型对象的ChallengeScript属性上。
最后设置上面这段JavaScript的预期运行结果,非常简单:
e.RequiredResponse = (width * height).ToString();
需要注意的是要将预期运行结果赋值给e.RequiredResponse,即NoBotEventArgs类型对象的RequiredResponse属性。
这样,若客户端为真正的浏览器的话,则设置于e.ChallengeScript中的这段JavaScript将正常执行,并如我们所料地返回和e.RequiredResponse中完全一样的预期结果。若是二者不匹配,则即可认为该客户端为忽略了JavaScript的机器人程序。
完整的noBot_GenerateChallengeAndResponse()代码如下:
protected void noBot_GenerateChallengeAndResponse(object sender, NoBotEventArgs e)
{
Panel noBotPanel = new Panel();
Random rand = new Random();
int width = rand.Next(80);
int height = rand.Next(120);
noBotPanel.ID = string.Format("noBotPanel{0}", rand.Next(1000));
noBotPanel.Width = width;
noBotPanel.Height = height;
noBotPanel.Style.Add(HtmlTextWriterStyle.Visibility, "hidden");
noBotPanel.Style.Add(HtmlTextWriterStyle.Position, "absolute");
(sender as NoBot).Controls.Add(noBotPanel);
e.ChallengeScript = string.Format("var noBotPanel = document.getElementById('{0}'); noBotPanel.offsetWidth * noBotPanel.offsetHeight;", noBotPanel.ClientID);
e.RequiredResponse = (width * height).ToString();
}
接下来同样需要编写的还有Page_Load()函数,其中我们将使用NoBot控件进行验证。因为只有在回送时才有验证的必要,所以我们忽略掉页面第一次加载的情况:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
……
}
}
我们将在上述代码中满足IsPostBack的条件下编写我们的验证代码。在其中新建一个NoBotState类型的枚举,NoBot控件的验证结果就将存放于该枚举中:
NoBotState state;
NoBotState枚举的可选值有如下几种:
1. Valid:表示验证通过。
2. InvalidBadResponse:表示前面自定义的JavaScript脚本(即e.ChallengeScript)的运行结果和预期结果(即e.RequiredResponse)不符,验证失败。
3. InvalidResponseTooSoon:表示客户端完成表单的时间小于ResponseMinimumDelaySeconds所指定的时间,验证失败。
4. InvalidAddressTooActive:表示客户端在CutoffWindowSeconds指定的窗口时间内的请求超过了CutoffMaximumInstances所指定的数量,验证失败。
5. InvalidBadSession:表示会话状态验证失败,可能是客户端并没有保存会话状态,验证失败。
6. InvalidUnknown:未知错误,验证失败。
然后将该NoBotState枚举的引用传递到NoBot控件的IsValid()方法中,该方法将返回一个布尔值,代表验证是否成功。同时,传递 进入的NoBotState也将被设定为相应的枚举值。这样,我们即可通过分辨IsValid()方法的返回值判断验证是否成功,并作以相应操作:
if (noBot.IsValid(out state))
{
……
}
else
{
……
}
在验证通过时,我们将给出一个示例性的提示:
lbResult.Text = "您的信息已经被提交!";
若验证失败,则将同样给出详细的错误提示:
string errorMessage = string.Empty;
switch (state)
{
case NoBotState.InvalidAddressTooActive :
errorMessage = "该IP地址在短时间内提交了过多的请求。";
break;
case NoBotState.InvalidBadResponse :
errorMessage = "浏览器中检测脚本未被运行或运行结果不正确。";
break;
case NoBotState.InvalidBadSession :
errorMessage = "ASP.NET会话状态不可用。";
break;
case NoBotState.InvalidResponseTooSoon :
errorMessage = "两次回送时间间隔过短。";
break;
case NoBotState.InvalidUnknown :
errorMessage = "未知错误。";
break;
}
lbResult.Text = string.Format("请求被拒绝,原因:{0}", errorMessage);
出于演示的目的,上述代码才如此耐心地对原因一一解释。在实际的应用程序中,我们完全没有必要如此的“友善”,简单地提示“怀疑为机器人程序”即 可,或是更加干脆地用Response.End()结束本次HTTP会话,给机器人程序以颜色,也免得让其了解我们程序中更多的NoBot实现细节。
作为参考,下面列出Page_Load()函数的完整代码:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
NoBotState state;
if (noBot.IsValid(out state))
{
lbResult.Text = "您的信息已经被提交!";
}
else
{
string errorMessage = string.Empty;
switch (state)
{
case NoBotState.InvalidAddressTooActive :
errorMessage = "该IP地址在短时间内提交了过多的请求。";
break;
case NoBotState.InvalidBadResponse :
errorMessage = "浏览器中检测脚本未被运行或运行结果不正确。";
break;
case NoBotState.InvalidBadSession :
errorMessage = "ASP.NET会话状态不可用。";
break;
case NoBotState.InvalidResponseTooSoon :
errorMessage = "两次回送时间间隔过短。";
break;
case NoBotState.InvalidUnknown :
errorMessage = "未知错误。";
break;
}
lbResult.Text = string.Format("请求被拒绝,原因:{0}", errorMessage);
}
}
}
这样即完成了本示例程序,编译并在浏览器中查看该页面,将如图10-3所示。
图10-3 初始化的表单
在文本框中输入一些文字,确保等待了2秒钟之后再提交页面,将看到“您的信息已经被提交!”验证通过信息,如图10-4所示。
图10-4 验证通过
迅速再点一下提交(2秒钟之内),将看到如图10-5所示的“请求被拒绝,原因:两次回送时间间隔过短。”验证失败信息。
图10-5 两次回送时间间隔过短,验证失败
若是在10秒钟之内提交次数超过两次,将看到如图10-6所示的“请求被拒绝,原因:该IP地址在短时间内提交了过多的请求。”验证失败信息。
图10-6 同一IP地址在短时间内提交了过多的请求,验证失败
若是在浏览器中禁用了的JavaScript,则将看到如图10-7所示的“请求被拒绝,原因:浏览器中检测脚本未被运行或运行结果不正确。”验证失败信息。
图10-7 浏览器中检测脚本未被运行或运行结果不正确,验证失败
10.1.4 常见问题以及使用技巧
NoBot可以完全代替传统的验证图片么?
不可以。按照当前的计算机技术来看,验证图片将始终是最为精确的、无可替代的辨别机器人程序和真正用户的最佳方法。对于NoBot控件所采用的判断 规则,机器人程序均能够通过某种方式进行模拟并巧妙地绕开。且由于NoBot控件需要统计过多的信息,例如某个时间段内每个IP的提交次数、每个页面的提交时间间隔等,也会在某种程度上影响服务器端的执行效率。同时,若NoBot控件配置不当,或是用户使用某些不支持JavaScript的浏览器(例如移 动设备中的浏览器),则极易导致较高的误判断率乃至根本无法通过验证,反而影响了用户体验。
而若是配置得当且服务器端资源充沛,则NoBot控件的优势也非常明显。所以,在选择合适的验证方法时,上述问题均要结合实际应用场景考虑周全,并做出恰当的决定。
如何选择强制浏览器执行的JavaScript,即ChallengeScript?
由于这段JavaScript难以调试,所以应该尽可能的简单。同时,为了避免机器人程序的成功预测,其中也要包含相当的不确定性。由此,前面示例程序中演示的创建
最后设置上面这段JavaScript的预期运行结果,非常简单:
e.RequiredResponse = (width * height).ToString();
需要注意的是要将预期运行结果赋值给e.RequiredResponse,即NoBotEventArgs类型对象的RequiredResponse属性。
这样,若客户端为真正的浏览器的话,则设置于e.ChallengeScript中的这段JavaScript将正常执行,并如我们所料地返回和e.RequiredResponse中完全一样的预期结果。若是二者不匹配,则即可认为该客户端为忽略了JavaScript的机器人程序。
完整的noBot_GenerateChallengeAndResponse()代码如下:
protected void noBot_GenerateChallengeAndResponse(object sender, NoBotEventArgs e)
{
Panel noBotPanel = new Panel();
Random rand = new Random();
int width = rand.Next(80);
int height = rand.Next(120);
noBotPanel.ID = string.Format("noBotPanel{0}", rand.Next(1000));
noBotPanel.Width = width;
noBotPanel.Height = height;
noBotPanel.Style.Add(HtmlTextWriterStyle.Visibility, "hidden");
noBotPanel.Style.Add(HtmlTextWriterStyle.Position, "absolute");
(sender as NoBot).Controls.Add(noBotPanel);
e.ChallengeScript = string.Format("var noBotPanel = document.getElementById('{0}'); noBotPanel.offsetWidth * noBotPanel.offsetHeight;", noBotPanel.ClientID);
e.RequiredResponse = (width * height).ToString();
}
接下来同样需要编写的还有Page_Load()函数,其中我们将使用NoBot控件进行验证。因为只有在回送时才有验证的必要,所以我们忽略掉页面第一次加载的情况:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
……
}
}
我们将在上述代码中满足IsPostBack的条件下编写我们的验证代码。在其中新建一个NoBotState类型的枚举,NoBot控件的验证结果就将存放于该枚举中:
NoBotState state;
NoBotState枚举的可选值有如下几种:
1. Valid:表示验证通过。
2. InvalidBadResponse:表示前面自定义的JavaScript脚本(即e.ChallengeScript)的运行结果和预期结果(即e.RequiredResponse)不符,验证失败。
3. InvalidResponseTooSoon:表示客户端完成表单的时间小于ResponseMinimumDelaySeconds所指定的时间,验证失败。
4. InvalidAddressTooActive:表示客户端在CutoffWindowSeconds指定的窗口时间内的请求超过了CutoffMaximumInstances所指定的数量,验证失败。
5. InvalidBadSession:表示会话状态验证失败,可能是客户端并没有保存会话状态,验证失败。
6. InvalidUnknown:未知错误,验证失败。
然后将该NoBotState枚举的引用传递到NoBot控件的IsValid()方法中,该方法将返回一个布尔值,代表验证是否成功。同时,传递 进入的NoBotState也将被设定为相应的枚举值。这样,我们即可通过分辨IsValid()方法的返回值判断验证是否成功,并作以相应操作:
if (noBot.IsValid(out state))
{
……
}
else
{
……
}
在验证通过时,我们将给出一个示例性的提示:
lbResult.Text = "您的信息已经被提交!";
若验证失败,则将同样给出详细的错误提示:
string errorMessage = string.Empty;
switch (state)
{
case NoBotState.InvalidAddressTooActive :
errorMessage = "该IP地址在短时间内提交了过多的请求。";
break;
case NoBotState.InvalidBadResponse :
errorMessage = "浏览器中检测脚本未被运行或运行结果不正确。";
break;
case NoBotState.InvalidBadSession :
errorMessage = "ASP.NET会话状态不可用。";
break;
case NoBotState.InvalidResponseTooSoon :
errorMessage = "两次回送时间间隔过短。";
break;
case NoBotState.InvalidUnknown :
errorMessage = "未知错误。";
break;
}
lbResult.Text = string.Format("请求被拒绝,原因:{0}", errorMessage);
出于演示的目的,上述代码才如此耐心地对原因一一解释。在实际的应用程序中,我们完全没有必要如此的“友善”,简单地提示“怀疑为机器人程序”即 可,或是更加干脆地用Response.End()结束本次HTTP会话,给机器人程序以颜色,也免得让其了解我们程序中更多的NoBot实现细节。
作为参考,下面列出Page_Load()函数的完整代码:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
NoBotState state;
if (noBot.IsValid(out state))
{
lbResult.Text = "您的信息已经被提交!";
}
else
{
string errorMessage = string.Empty;
switch (state)
{
case NoBotState.InvalidAddressTooActive :
errorMessage = "该IP地址在短时间内提交了过多的请求。";
break;
case NoBotState.InvalidBadResponse :
errorMessage = "浏览器中检测脚本未被运行或运行结果不正确。";
break;
case NoBotState.InvalidBadSession :
errorMessage = "ASP.NET会话状态不可用。";
break;
case NoBotState.InvalidResponseTooSoon :
errorMessage = "两次回送时间间隔过短。";
break;
case NoBotState.InvalidUnknown :
errorMessage = "未知错误。";
break;
}
lbResult.Text = string.Format("请求被拒绝,原因:{0}", errorMessage);
}
}
}
这样即完成了本示例程序,编译并在浏览器中查看该页面,将如图10-3所示。
图10-3 初始化的表单
在文本框中输入一些文字,确保等待了2秒钟之后再提交页面,将看到“您的信息已经被提交!”验证通过信息,如图10-4所示。
图10-4 验证通过
迅速再点一下提交(2秒钟之内),将看到如图10-5所示的“请求被拒绝,原因:两次回送时间间隔过短。”验证失败信息。
图10-5 两次回送时间间隔过短,验证失败
若是在10秒钟之内提交次数超过两次,将看到如图10-6所示的“请求被拒绝,原因:该IP地址在短时间内提交了过多的请求。”验证失败信息。
图10-6 同一IP地址在短时间内提交了过多的请求,验证失败
若是在浏览器中禁用了的JavaScript,则将看到如图10-7所示的“请求被拒绝,原因:浏览器中检测脚本未被运行或运行结果不正确。”验证失败信息。
图10-7 浏览器中检测脚本未被运行或运行结果不正确,验证失败
10.1.4 常见问题以及使用技巧
NoBot可以完全代替传统的验证图片么?
不可以。按照当前的计算机技术来看,验证图片将始终是最为精确的、无可替代的辨别机器人程序和真正用户的最佳方法。对于NoBot控件所采用的判断 规则,机器人程序均能够通过某种方式进行模拟并巧妙地绕开。且由于NoBot控件需要统计过多的信息,例如某个时间段内每个IP的提交次数、每个页面的提交时间间隔等,也会在某种程度上影响服务器端的执行效率。同时,若NoBot控件配置不当,或是用户使用某些不支持JavaScript的浏览器(例如移 动设备中的浏览器),则极易导致较高的误判断率乃至根本无法通过验证,反而影响了用户体验。
而若是配置得当且服务器端资源充沛,则NoBot控件的优势也非常明显。所以,在选择合适的验证方法时,上述问题均要结合实际应用场景考虑周全,并做出恰当的决定。
如何选择强制浏览器执行的JavaScript,即ChallengeScript?
由于这段JavaScript难以调试,所以应该尽可能的简单。同时,为了避免机器人程序的成功预测,其中也要包含相当的不确定性。由此,前面示例程序中演示的创建
并检测其高度和宽度的乘积的方法非常适合:既足够简单,也有着相当的随机性,足够让机器人程序难以捉摸。
[1]CAPTCHA即Completely Automated Public Turing Test to Tell Computers and Humans Apart(全自动的公开图灵测试),其目的是让计算机生成区分计算机和人类的程序算法,这种程序必须能够生成并评价出人类能很容易通过但计算机却难以通过的测试。目前常见的验证图片等都属于CAPTCHA。若想了解更多,请访问“The CAPTCHA Project”网站:http://www.captcha.net/。
[2] ID属性起到控件标志符的作用,我们都很熟悉,限于篇幅这里不赘。下同。
19. NumericUpDown
【功能概述】
实现Winform里面的Updown控件,可以自定义最大值最小值增减步长,同时还可以使用值列表或者调用Web Service来决定下一个值是什么。上下按钮的图片同样是可以自定义的。
【细节】
(1)普通整数增减
(2)值列表循环显示比如下面的第二个例子RefValues
(3)调用Web Service的格式:
TargetControlID="TextBox1"
Width="100"
RefValues="January;February;March;April"
TargetButtonDownID="Button1"
TargetButtonUpID="Button2"
ServiceDownPath="WebService1.asmx"
ServiceDownMethod="PrevValue"
ServiceUpPath="WebService1.asmx"
ServiceUpMethod="NextValue"
Tag="1" />
(4)上下按钮如果不需美化就这样使用:TargetButtonDownID=" " TargetButtonUpID=" "
【示意代码】
代码示意:
TargetControlID="TextBox1" Width="120" RefValues=""
ServiceDownMethod="" ServiceUpMethod="" TargetButtonDownID="" TargetButtonUpID="" />
TargetControlID="TextBox2" Width="120" RefValues="January;February;March;April;May;June;July;August;September;October;November;December"
ServiceDownMethod="" ServiceUpMethod="" TargetButtonDownID="" TargetButtonUpID="" />
TargetControlID="TextBox4" Width="80" TargetButtonDownID="img1"
TargetButtonUpID="img2" RefValues="" ServiceDownMethod="" ServiceUpMethod="" />
20. PagingBulletedList
【功能概述】
PagingBulletedList 扩展BulletedList的分页功能并实现客户端的排序分页。这里提供的分页是相当灵活的有各种分页方法供选择。
【细节】
(1)可以控制每页最多显示多少条,是否排序
(2)IndexSize表示index headings 的字符数,如果MaxItemPerPage设置了概属性被忽略
(3)MaxItemPerPage分页每页最大条数
【示意代码】
代码示意:
TargetControlID="BulletedList1"
ClientSort="true"
IndexSize="1"
Separator=" - "
SelectIndexCssClass="selectIndex"
UnselectIndexCssClass="unselectIndex" />
21. PasswordStrength
【功能】
验证密码强度,微软Live注册的时候就是用的这个效果。
【细节】
StrengthIndicatorType两种显示方式:文字提示,进度条提示。
示例中Textbox1 Textbox3都没有添加TextMode="Password" 所以在界面上我们可以输入中文;而且输入中文很快就达到较高安全度,当然这没有什么用处。
【示意代码】
代码示意:
StrengthIndicatorType="Text" PreferredPasswordLength="10" PrefixText="Strength:"
HelpStatusLabelID="TextBox1_HelpLabel" TextCssClass="TextIndicator_TextBox1" TextStrengthDescriptions="Very Poor;Weak;Average;Strong;Excellent"
MinimumNumericCharacters="0" MinimumSymbolCharacters="0" RequiresUpperAndLowerCaseCharacters="false"/>
StrengthIndicatorType="BarIndicator" PreferredPasswordLength="15" HelpStatusLabelID="TextBox2_HelpLabel"
BarIndicatorCssClass="BarIndicator_TextBox2" BarBorderCssClass="BarBorder_TextBox2"
MinimumNumericCharacters="1" MinimumSymbolCharacters="1" RequiresUpperAndLowerCaseCharacters="true" />
StrengthIndicatorType="Text" PreferredPasswordLength="20" PrefixText="Meets Policy? " TextCssClass="TextIndicator_TextBox3"
MinimumNumericCharacters="2" MinimumSymbolCharacters="2" RequiresUpperAndLowerCaseCharacters="true"
TextStrengthDescriptions="Not at all;Very Low compliance;Low Compliance;Average Compliance;Good Compliance;Very High Compliance;Yes"
HelpHandleCssClass="TextIndicator_TextBox3_Handle" HelpHandlePosition="LeftSide" />
22.PopupControl
【功能概述】
PopupControl任何控件上都可以弹出任何内容,跟HoverMenu功能类似。Popup 窗口一般是放在ASP.NET AJAX UpdatePanel中, 因此它能够完成服务器端的处理之后更能新数据
显示. Popup Window 可以包含任何内容包括 ASP.NET server controls, HTML elements, etc.
【细节】
(1)TargetControlID - The ID of the control to attach to
(2)PopupControlID - The ID of the control to display
(3)CommitProperty -属性来标识返回的值
(4) CommitScript -把返回结果值通过脚本处理,用到CommitProperty
【代码示意】
PopupControlID="Panel2" CommitProperty="value" CommitScript="e.value += ' - do not forget!';" Position="Bottom" />
23.Rating
【功能概述】
使用星级表示等级,鼠标操作;
【细节】
鼠标移动等级也会变,而你真正要修改还要点击一下;这是延续了WP10里面等级评定控件的传统,也许这样设计是真的有道理,我不清除。
【示意代码】
代码示意:
CurrentRating="2"
MaxRating="5"
StarCssClass="ratingStar"
WaitingStarCssClass="savedRatingStar"
FilledStarCssClass="filledRatingStar"
EmptyStarCssClass="emptyRatingStar"
OnChanged="ThaiRating_Changed" />
24.ReorderList
【功能概述】
ReorderList是一个全新的控件。它可以实现逐条列出数据并实现交互。用户简单的拖拽就可以改变数据的排列顺序并更新到数据源。在本控件中如果SortOrderField 属性设置之后排序将自动完成。
【细节】
(1)绑定数据,拖动数据之后数据将被更新到绑定源
(2)它不是已有控件的扩展是全新的服务器端控件,只是它对Ajax行为是敏感的
(3)重排的实现有两种方式:CallBack PostBack 前者的发生在页面上是没有PostBack的(也就是没有刷新页面)
(4) 而数据添加或者编辑的时候就必须要使用PostBack来同步服务器端的数据状态
(5)PostbackOnReorder就是针对两种策略进行选择
【示意代码】
代码示意:
DataSourceID="ObjectDataSource1"
DragHandleAlignment="Left"
ItemInsertLocation="Beginning"
DataKeyField="ItemID"
SortOrderField="Priority"
AllowReorder="true">
这个控件是非常独立,并且还是适用于表现Buleted的数据,二维数据就无能为例了
DataSourceID="ObjectDataSource1" 这是必须要有的!下面是它的Template框架:
DragHandleAlignment="Left" ItemInsertLocation="Beginning" DataKeyField="ItemID" SortOrderField="Priority">
25. ResizableControl
【功能概述】
就像设计状态一样可以拖动修改大小,可是有什么实际的意义么,放大字体?没有想到
【 细节】
(1) HandleCssClass - The name of the CSS class to apply to the resize handle 这个属性必须要有!
(2) WEB2.0时代用户什么都是可以自定义的??难道是这个原则下的产物么??不理解
(3) 在前卫的飞鸽网站上我都一直没有看到关于ResizableControl的应用,期待一个成功的应用
【示意代码】
代码示意:
TargetControlID="PanelImage"
HandleCssClass="handleImage"
ResizableCssClass="resizingImage"
MinimumWidth="50"
MinimumHeight="20"
MaximumWidth="260"
MaximumHeight="130"
OnClientResize="OnClientResizeImage"
HandleOffsetX="3"
HandleOffsetY="3" />
26. RoundedCorners
【功能】
控件圆角 纯粹是控制外观的了,什么时候审美疲劳了还要改。据说GUI风格也是N年一轮回,这让我想起来了一个27KB的QQ,命令行界面,真的是这样么?穿孔纸带据说是第一代GUI,不会有一天真的回到那个时代吧?
【细节】
(1)还有一个非常非常细节的地方:你必须要设置 CssClass="roundedPanel"要不然不起作用
(2) Radius设置弧度,默认是5
(3)只适用于容器 WebControl
【示意代码】
代码示意:
27. Slider
【功能概述】
实现WinForm中的Slider控件效果,新浪论坛用来分页了,还有的用来调整“时间----------|----热度”,创意!
【细节】
(1) 修改文本框的值也可以影响Slider的状态
【示意代码】
代码示意:
BehaviorID="Slider2"
TargetControlID="Slider2"
BoundControlID="TextBox1"
Orientation="Horizontal"
EnableHandleAnimation="true"
Minimum="0"
Maximum="100"
/>
28. Tabs NEW!!!
Tabs是我认为这一次新增控件中最实用的好东东, 在编码风格上与所有嵌套式的控件一样:
OnClientActiveTabChanged="ClientFunction"
Height="150px">
HeaderText="Signature and Bio"
...
/>
Demo效果让我们很容易想到最近改版之后的网页主页和新浪主页 和Accordion比较一下各有千秋,是对经典WinForm的一种继承。
29 .TextBoxWatermark
【功能概述】
对文本框进行扩展,文本水印效果。
看了几十个WEB2.0的网站,没想到,见到最多的就是这种水印效果,看来很受欢迎。
【示意代码】
代码示意:
30. ToggleButton
【功能概述】
就是把一个CheckBox的逻辑应用到一个按钮上,于是就有了双态按钮这么个玩意,有点意思啊
实际上示例页面并没有突出这个控件功能上的优势,对这个控件的操作引起页面上数据的更新,这才是CheckBox控件封装成Button的最终原因。
【示意代码】
ImageHeight="19" UncheckedImageUrl="Image/down.gif" CheckedImageUrl="Image/up.gif" CheckedImageAlternateText="Check"
UncheckedImageAlternateText="UnCheck" />
31.UpdatePanelAnimation
【功能概述】
更新动画效果,个人认为应用于时间较短的场合,时间长了这个动画就有点不合适了,毕竟这是一个过渡效果;时间长还是UpdateProgress比较好。
【细节】
代码结构简单但是要说的东西很多,回头再说写专题吧
代码示意:
runat="server" TargetControlID="up">
32. ValidatorCallout
【功能概述】
Windows系统中最常见的气泡提示,比如你磁盘空间不足的时候。是对数据验证控件的扩展,比较实用,页面效果的确是比以前那
[1]CAPTCHA即Completely Automated Public Turing Test to Tell Computers and Humans Apart(全自动的公开图灵测试),其目的是让计算机生成区分计算机和人类的程序算法,这种程序必须能够生成并评价出人类能很容易通过但计算机却难以通过的测试。目前常见的验证图片等都属于CAPTCHA。若想了解更多,请访问“The CAPTCHA Project”网站:http://www.captcha.net/。
[2] ID属性起到控件标志符的作用,我们都很熟悉,限于篇幅这里不赘。下同。
19. NumericUpDown
【功能概述】
实现Winform里面的Updown控件,可以自定义最大值最小值增减步长,同时还可以使用值列表或者调用Web Service来决定下一个值是什么。上下按钮的图片同样是可以自定义的。
【细节】
(1)普通整数增减
(2)值列表循环显示比如下面的第二个例子RefValues
(3)调用Web Service的格式:
TargetControlID="TextBox1"
Width="100"
RefValues="January;February;March;April"
TargetButtonDownID="Button1"
TargetButtonUpID="Button2"
ServiceDownPath="WebService1.asmx"
ServiceDownMethod="PrevValue"
ServiceUpPath="WebService1.asmx"
ServiceUpMethod="NextValue"
Tag="1" />
(4)上下按钮如果不需美化就这样使用:TargetButtonDownID=" " TargetButtonUpID=" "
【示意代码】
代码示意:
TargetControlID="TextBox1" Width="120" RefValues=""
ServiceDownMethod="" ServiceUpMethod="" TargetButtonDownID="" TargetButtonUpID="" />
TargetControlID="TextBox2" Width="120" RefValues="January;February;March;April;May;June;July;August;September;October;November;December"
ServiceDownMethod="" ServiceUpMethod="" TargetButtonDownID="" TargetButtonUpID="" />
TargetControlID="TextBox4" Width="80" TargetButtonDownID="img1"
TargetButtonUpID="img2" RefValues="" ServiceDownMethod="" ServiceUpMethod="" />
20. PagingBulletedList
【功能概述】
PagingBulletedList 扩展BulletedList的分页功能并实现客户端的排序分页。这里提供的分页是相当灵活的有各种分页方法供选择。
【细节】
(1)可以控制每页最多显示多少条,是否排序
(2)IndexSize表示index headings 的字符数,如果MaxItemPerPage设置了概属性被忽略
(3)MaxItemPerPage分页每页最大条数
【示意代码】
代码示意:
TargetControlID="BulletedList1"
ClientSort="true"
IndexSize="1"
Separator=" - "
SelectIndexCssClass="selectIndex"
UnselectIndexCssClass="unselectIndex" />
21. PasswordStrength
【功能】
验证密码强度,微软Live注册的时候就是用的这个效果。
【细节】
StrengthIndicatorType两种显示方式:文字提示,进度条提示。
示例中Textbox1 Textbox3都没有添加TextMode="Password" 所以在界面上我们可以输入中文;而且输入中文很快就达到较高安全度,当然这没有什么用处。
【示意代码】
代码示意:
StrengthIndicatorType="Text" PreferredPasswordLength="10" PrefixText="Strength:"
HelpStatusLabelID="TextBox1_HelpLabel" TextCssClass="TextIndicator_TextBox1" TextStrengthDescriptions="Very Poor;Weak;Average;Strong;Excellent"
MinimumNumericCharacters="0" MinimumSymbolCharacters="0" RequiresUpperAndLowerCaseCharacters="false"/>
StrengthIndicatorType="BarIndicator" PreferredPasswordLength="15" HelpStatusLabelID="TextBox2_HelpLabel"
BarIndicatorCssClass="BarIndicator_TextBox2" BarBorderCssClass="BarBorder_TextBox2"
MinimumNumericCharacters="1" MinimumSymbolCharacters="1" RequiresUpperAndLowerCaseCharacters="true" />
StrengthIndicatorType="Text" PreferredPasswordLength="20" PrefixText="Meets Policy? " TextCssClass="TextIndicator_TextBox3"
MinimumNumericCharacters="2" MinimumSymbolCharacters="2" RequiresUpperAndLowerCaseCharacters="true"
TextStrengthDescriptions="Not at all;Very Low compliance;Low Compliance;Average Compliance;Good Compliance;Very High Compliance;Yes"
HelpHandleCssClass="TextIndicator_TextBox3_Handle" HelpHandlePosition="LeftSide" />
22.PopupControl
【功能概述】
PopupControl任何控件上都可以弹出任何内容,跟HoverMenu功能类似。Popup 窗口一般是放在ASP.NET AJAX UpdatePanel中, 因此它能够完成服务器端的处理之后更能新数据
显示. Popup Window 可以包含任何内容包括 ASP.NET server controls, HTML elements, etc.
【细节】
(1)TargetControlID - The ID of the control to attach to
(2)PopupControlID - The ID of the control to display
(3)CommitProperty -属性来标识返回的值
(4) CommitScript -把返回结果值通过脚本处理,用到CommitProperty
【代码示意】
PopupControlID="Panel2" CommitProperty="value" CommitScript="e.value += ' - do not forget!';" Position="Bottom" />
23.Rating
【功能概述】
使用星级表示等级,鼠标操作;
【细节】
鼠标移动等级也会变,而你真正要修改还要点击一下;这是延续了WP10里面等级评定控件的传统,也许这样设计是真的有道理,我不清除。
【示意代码】
代码示意:
CurrentRating="2"
MaxRating="5"
StarCssClass="ratingStar"
WaitingStarCssClass="savedRatingStar"
FilledStarCssClass="filledRatingStar"
EmptyStarCssClass="emptyRatingStar"
OnChanged="ThaiRating_Changed" />
24.ReorderList
【功能概述】
ReorderList是一个全新的控件。它可以实现逐条列出数据并实现交互。用户简单的拖拽就可以改变数据的排列顺序并更新到数据源。在本控件中如果SortOrderField 属性设置之后排序将自动完成。
【细节】
(1)绑定数据,拖动数据之后数据将被更新到绑定源
(2)它不是已有控件的扩展是全新的服务器端控件,只是它对Ajax行为是敏感的
(3)重排的实现有两种方式:CallBack PostBack 前者的发生在页面上是没有PostBack的(也就是没有刷新页面)
(4) 而数据添加或者编辑的时候就必须要使用PostBack来同步服务器端的数据状态
(5)PostbackOnReorder就是针对两种策略进行选择
【示意代码】
代码示意:
DataSourceID="ObjectDataSource1"
DragHandleAlignment="Left"
ItemInsertLocation="Beginning"
DataKeyField="ItemID"
SortOrderField="Priority"
AllowReorder="true">
这个控件是非常独立,并且还是适用于表现Buleted的数据,二维数据就无能为例了
DataSourceID="ObjectDataSource1" 这是必须要有的!下面是它的Template框架:
DragHandleAlignment="Left" ItemInsertLocation="Beginning" DataKeyField="ItemID" SortOrderField="Priority">
25. ResizableControl
【功能概述】
就像设计状态一样可以拖动修改大小,可是有什么实际的意义么,放大字体?没有想到
【 细节】
(1) HandleCssClass - The name of the CSS class to apply to the resize handle 这个属性必须要有!
(2) WEB2.0时代用户什么都是可以自定义的??难道是这个原则下的产物么??不理解
(3) 在前卫的飞鸽网站上我都一直没有看到关于ResizableControl的应用,期待一个成功的应用
【示意代码】
代码示意:
TargetControlID="PanelImage"
HandleCssClass="handleImage"
ResizableCssClass="resizingImage"
MinimumWidth="50"
MinimumHeight="20"
MaximumWidth="260"
MaximumHeight="130"
OnClientResize="OnClientResizeImage"
HandleOffsetX="3"
HandleOffsetY="3" />
26. RoundedCorners
【功能】
控件圆角 纯粹是控制外观的了,什么时候审美疲劳了还要改。据说GUI风格也是N年一轮回,这让我想起来了一个27KB的QQ,命令行界面,真的是这样么?穿孔纸带据说是第一代GUI,不会有一天真的回到那个时代吧?
【细节】
(1)还有一个非常非常细节的地方:你必须要设置 CssClass="roundedPanel"要不然不起作用
(2) Radius设置弧度,默认是5
(3)只适用于容器 WebControl
【示意代码】
代码示意:
27. Slider
【功能概述】
实现WinForm中的Slider控件效果,新浪论坛用来分页了,还有的用来调整“时间----------|----热度”,创意!
【细节】
(1) 修改文本框的值也可以影响Slider的状态
【示意代码】
代码示意:
BehaviorID="Slider2"
TargetControlID="Slider2"
BoundControlID="TextBox1"
Orientation="Horizontal"
EnableHandleAnimation="true"
Minimum="0"
Maximum="100"
/>
28. Tabs NEW!!!
Tabs是我认为这一次新增控件中最实用的好东东, 在编码风格上与所有嵌套式的控件一样:
OnClientActiveTabChanged="ClientFunction"
Height="150px">
HeaderText="Signature and Bio"
...
/>
Demo效果让我们很容易想到最近改版之后的网页主页和新浪主页 和Accordion比较一下各有千秋,是对经典WinForm的一种继承。
29 .TextBoxWatermark
【功能概述】
对文本框进行扩展,文本水印效果。
看了几十个WEB2.0的网站,没想到,见到最多的就是这种水印效果,看来很受欢迎。
【示意代码】
代码示意:
30. ToggleButton
【功能概述】
就是把一个CheckBox的逻辑应用到一个按钮上,于是就有了双态按钮这么个玩意,有点意思啊
实际上示例页面并没有突出这个控件功能上的优势,对这个控件的操作引起页面上数据的更新,这才是CheckBox控件封装成Button的最终原因。
【示意代码】
ImageHeight="19" UncheckedImageUrl="Image/down.gif" CheckedImageUrl="Image/up.gif" CheckedImageAlternateText="Check"
UncheckedImageAlternateText="UnCheck" />
31.UpdatePanelAnimation
【功能概述】
更新动画效果,个人认为应用于时间较短的场合,时间长了这个动画就有点不合适了,毕竟这是一个过渡效果;时间长还是UpdateProgress比较好。
【细节】
代码结构简单但是要说的东西很多,回头再说写专题吧
代码示意:
runat="server" TargetControlID="up">
32. ValidatorCallout
【功能概述】
Windows系统中最常见的气泡提示,比如你磁盘空间不足的时候。是对数据验证控件的扩展,比较实用,页面效果的确是比以前那