掩码编辑功能的必要性
在 HTML 中,接受输入数据的唯一方式是使用 <input> 标记。在 ASP.NET 中,只是使用 TextBox 控件对输入标记进行了封装。此控件存在的一个问题是:它并不限制用户可以在其中键入的内容。但是,通过使用少量的 JavaScript 代码,您可以筛选掉不需要的文本。这就是上个月所介绍的内容。这个月我将添加掩码编辑功能,该功能允许在键入字符时对其进行筛选,并允许字符以区域特定格式显示。掩码编辑功能可用于筛选、验证、自动设置格式和本地化。还可将该功能应用于许多真实数据类型,包括日期、货币、时间、邮政编码、电话号码、社会保险号码或增值税 ID 等。在 AJAX 控件工具包中,MaskedEdit 扩展器是一个免费组件,将其附加到 TextBox 控件后,您便可以对许多常见情况下的输入行为进行控制。
MaskedEdit 扩展器
在 AJAX 控件工具包中,MaskedEdit 扩展器支持 MaskEditType 枚举类型所指定的某些数据格式:2008年度***技术图书与原创作者评选颁奖典礼
public enum MaskedEditType { None, Date, Number, Time, DateTime } |
您可以使用该扩展器输入数字、日期、时间和日期/时间。扩展器根据给定的区域性设置来决定输出格式。以下代码段显示了对接受日期输入的文本框使用 MaskedEdit 扩展器的典型方式:
<asp:TextBox runat="server" ID="TextBox1" /> |
图 A 所列。主要通过两个属性来定义输入掩码:Mask 和 MaskType。Mask 的默认值为 "",用于指定扩展器可接受的字符的掩码。MaskType 的默认值为 "",用于使用 MaskedEditType 枚举所定义的任意值来指示掩码类型。
FigureAMaskedEdit 扩展器属性
属性 |
默认值 |
说明 |
AcceptAMPM |
False |
一个布尔属性,用于指示是否应使用 AM/PM 符号。 |
AcceptNegative |
None |
指示是否允许使用负号 (-)。来自 MaskedEditShowSymbol 枚举的可用值包括:None、Left 和 Right。 |
AutoComplete |
True |
一个布尔属性,用于指示是否必须自动填写用户未指定的空掩码字符。 |
AutoCompleteValue |
"" |
指示在启用 Autocomplete 时要使用的默认字符。 |
Century |
1900 |
指示当年份的日期掩码仅有两位数字时要使用的世纪。 |
ClearMaskOnLostFocus |
True |
一个布尔属性,用于指示当文本框失去输入焦点时是否删除掩码。 |
ClearTextOnInvalid |
False |
一个布尔属性,用于指示当用户输入无效文本时是否清除文本框。 |
ClipboardEnabled |
True |
一个布尔属性,用于指示是否允许使用剪贴板进行复制/粘贴。 |
ClipboardText |
Your browser security settings don't permit the automatic execution of paste operations(浏览器的安全设置不允许自动执行粘贴操作) |
指示在执行剪贴板粘贴操作时要使用的提示文本。 |
CultureName |
"" |
获取并设置要使用的区域性设置的名称。 |
DisplayMoney |
None |
指示是否显示货币符号。来自 MaskedEditShowSymbol 枚举的可用值包括:None、Left 和 Right。 |
ErrorTooltipCssClass |
"" |
获取并设置工具提示消息的 CSS 类。 |
ErrorTooltipEnabled |
False |
一个布尔属性,用于指示当鼠标悬停在内容无效的文本框上方时,是否显示工具提示消息。 |
Filtered |
"" |
获取并设置在指定“C”占位符时掩码类型的有效字符列表。 |
InputDirection |
LeftToRight |
指示文本输入方向。来自 MaskedEditInputDirection 枚举的可用值包括:LeftToRight 和 RightToLeft。 |
Mask |
"" |
指定扩展器可接受的字符的掩码。 |
MaskType |
"" |
使用 MaskedEditType 枚举所定义的任意值来指示掩码类型。 |
MessageValidatorTip |
True |
一个布尔属性,用于指示当用户在文本框中键入内容时是否显示帮助消息。 |
OnBlurCssNegative |
"" |
获取并设置当文本框失去输入焦点且包含负值时所使用的 CSS 类。 |
OnFocusCssClass |
"" |
获取并设置当文本框获取到输入焦点时所使用的 CSS 类。 |
OnFocusCssNegative |
"" |
获取并设置当文本框获取到输入焦点且包含负值时所使用的 CSS 类。 |
OnInvalidCssClass |
"" |
获取并设置当文本无效时所使用的 CSS 类。 |
PromptCharacter |
_ |
获取并设置要为未指定的掩码字符使用的提示字符。 |
UserDateFormat |
None |
指示特定的日期格式。可用值由 MaskedEditUserDateFormat 枚举定义。 |
UserTimeFormat |
None |
指示特定的时间格式。可用值由 MaskedEditUserTimeFormat 枚举定义。 |
MaskType 属性通知扩展器目标控件将接受某个特定数据类型。Mask 属性(字符串类型)指示表示文本框的有效输入的字符序列。例如“12/6/07”和“12-09-2007”都是有效的日期,但它们使用不同的输入掩码。
要生成掩码,需使用预定义的符号作为占位符。图 1 列出了所支持的符号。例如,“999,999.99”掩码会使代码接受带有小数点的数字,至多有一个千位分隔符。图 2 显示了使用掩码编辑器扩展的文本框所显示的最终用户界面。货币符号的外观由 DisplayMoney 属性来控制,并会提示用户必须键入的每个字符。默认提示符为下划线,不过您可以通过 PromptCharacter 属性来更改提示符。
Figure1输入掩码预定义的占位符
符号 |
说明 |
9 |
数字字符 |
L |
字母 |
$ |
字母或空格 |
C |
通过 Filtered 属性定义的自定义写字符,区分大小 |
A |
通过 Filtered 属性定义的字母或自定义字符 |
N |
通过 Filtered 属性定义的数字或自定义字符 |
? |
任意字符 |
/ |
日期分隔符,取决于当前区域性设置 |
: |
时间分隔符,取决于当前区域性设置 |
. |
小数点,取决于当前区域性设置 |
, |
千位分隔符,取决于当前区域性设置 |
|
转义字符 |
{ |
重复掩码的起始符 |
} |
重复掩码的终止符 |
对于日期,还可以使用 AcceptAMPM、Century 等其他属性,甚至可以使用 MaskedEditUserDateFormat 枚举中指定的预定义格式之外的自定义用户格式,如下所示:
public enum MaskedEditUserDateFormat { None, DayMonthYear, DayYearMonth, MonthDayYear, MonthYearDay, YearDayMonth, YearMonthDay } |
影响 MaskedEdit 扩展器所应用的格式的许多设置都继承自当前区域性设置。CultureName 属性指示要应用的区域性设置。请注意,此设置将覆盖通过 @Page 指令中的 UICulture 属性为页面定义的区域性设置。
#p#
验证掩码输入
虽然掩码扩展器提供有动态格式设置功能,但是还有另外一个组件(掩码验证器)可确保将输入的任何文本都解析为预期类型:
<act:MaskedEditValidator |
图 B 列出了该验证器公开的属性。掩码文本框的 Text 属性返回带格式的文本。对于日期,该属性返回类似于“02/04/2007”的文本;而对于数字输入字段,该属性返回类似于“1,200.00”的文本。即使在页面上对用户显示了货币符号,Text 属性中也不包括货币符号。
FigureBMaskedEditValidator 属性
属性 |
说明 |
AcceptAMPM |
指示时间值是否接受 AM/PM。 |
ConTRolToValidate |
指示要验证的文本框的 ID。 |
ConTRolExtender |
指示附加到文本框的 MaskedEditExtender 控件的 ID。 |
ClientValidationFunction |
获取并设置用于自定义验证的客户端 JavaScript 函数的名称。 |
EmptyValueBlurredText |
获取并设置当文本框没有输入焦点且为空时所显示的消息。 |
EmptyValueMessage |
获取并设置当文本框具有输入焦点但为空时所显示的消息。 |
InitialValue |
获取并设置文本框的初始值。 |
InvalidValueMessage |
获取并设置当文本框具有输入焦点但内容无效时所显示的消息。 |
InvalidValueBlurredMessage |
获取并设置当文本框没有输入焦点但内容无效时所显示的消息。 |
IsValidEmpty |
指示文本框是否可以保留为空。 |
MaximumValue |
获取并设置输入的***值。 |
MaximumValueBlurredMessage |
获取并设置当超出***值且文本框没有焦点时所显示的消息。 |
MaximumValueMessage |
获取并设置当超出***值且文本框有焦点时所显示的消息。 |
MinimumValue |
获取并设置输入的最小值。 |
MinimumValueBlurredText |
获取并设置当超出最小值且文本框没有焦点时所显示的消息。 |
MinimumValueMessage |
获取并设置当超出最小值且文本框有焦点时所显示的消息。 |
ValidationExpression |
获取并设置用于验证输入的正则表达式。 |
TooltipMessage |
获取并设置当文本框具有输入焦点时所显示的消息。 |
那么,如何将 Text 返回的值解析为逻辑数据类型(日期或小数)呢?可以对 DateTime 和 Decimal 类型使用静态 Parse 方法。但是必须注意所使用的区域性设置。例如,“02/04/2007”可以表示 2 月 4 日(美国区域性设置),也可以表示 4 月 2 日(欧洲区域性设置)。事实上,并没有相关设置来保证输入页所使用的区域性设置与服务器页所使用的区域性设置相匹配。这就存在以下风险:用户根据欧洲区域性设置来键入日期,而将其作为美国区域性日期进行处理。更糟糕的是,使用意大利小数和千位分隔符在数字文本框中输入的值 1200 可能会导致引发异常,因为 Decimal 类型的解析器默认使用美国区域性设置。让我们来看看如何变通解决这些问题。
要牢记以下事实:除非显式设置 CultureName 属性,否则扩展器将默认使用 en-US 区域性设置。在服务器上,系统默认使用 Page 类上 UICulture 属性的值。
在您的 Codebehind 类中,首先获取反映用户界面所使用的区域性设置的 CultureInfo 对象。可以按照下面显示的方法继续操作:
string culture = "en-us"; |
然后调用 Parse 方法根据所选区域性设置指定格式提供程序:
NumberFormatInfo numberInfo = info.NumberFormat; |
图 3 显示了使用不同的区域性设置进行输入时同一页面的行为。
#p#
文本框自动完成
您肯定对自动完成功能非常熟悉。该功能会根据输入的前几个字符预测用户正在键入的单词。Internet Explorer 会记录已在地址栏和表单字段中键入的所有字符以自动完成填充。
当然,此功能完全基于浏览器,可以通过将 Autocomplete 属性设置为 On 或 Off,来打开或关闭 <input> 和 <form> 标记的自动完成功能。Autocomplete 属性不是标准的 HTML 属性,但是现在几乎所有浏览器都支持该属性。
AJAX Control Toolbox 中的 AutoComplete 扩展器提供与文本框控件相同的行为,但是它要求开发人员负责制订向用户提供建议的所有逻辑规则。该扩展器会创建一个下拉列表样式的面板,并将其放置在文本框的右下角。您可以根据自己的喜好设置面板的样式和动画效果。下面的代码将 Autocomplete 扩展器与一个文本框相关联:
<act:AutoCompleteExtender runat="server" ID="AutoComplete1" |
该扩展器绑定到用于提供列表填充词汇的 Web 服务。MinimumPrefixLength 属性指示控件何时调用该 Web 服务。已键入的文本将用作指定 Web 服务方法的输入。响应结果用于填充下拉列表。还可以启用缓存。这样,在多次键入相同的前缀时只需调用一次 Web 服务就可以了。此外,根据 Web 服务检索其数据的方式,还可以对服务器启用缓存,减少与数据库或其他远程数据存储区之间的额外往返行程。
图 C 列出了 AutoComplete 扩展器支持的所有属性。应注意,除了此处列出的属性,其他扩展器还具有另外的属性。TargetControlID 属性用于获取和设置扩展控件的 ID;Enabled 属性允许以编程方式打开和关闭扩展器的功能,该属性默认情况下设置为 True。还有 BehaviorID 属性,该属性用于设置提供扩展行为的客户端 JavaScript 对象的名称。***,还有两个重要属性:ClientState 和 EnableClientState。ClientState 属性是一个字符串属性,用于保持扩展器的客户端状态。该状态使用隐藏字段保持,字段的名称可以通过 ClientStateFieldID 属性进行设置。EnableClientState 属性是一个布尔属性,用于控制是否启用客户端状态。
FigureCAutoComplete 扩展器属性
属性 |
说明 |
Animations |
设置在显示或隐藏弹出面板时要播放的动画。 |
CompletionInterval |
获取并设置毫秒数,在该时间后,扩展器将使用绑定的 Web 服务获取建议。 |
CompletionListCssClass |
指示用于设置完成列表弹出面板的样式的 CSS 类。 |
CompletionListHighlightedItemCssClass |
指示用于设置完成列表弹出面板中突出显示项的样式的 CSS 类。 |
CompletionListItemCssClass |
指示用于设置完成列表弹出面板中项的样式的 CSS 类。 |
CompletionSetCount |
获取并设置从绑定的 Web 服务获取的建议数。默认值为 10。 |
ContextKey |
一个字符串属性,用于指示要传递给绑定的 Web 服务的任意页面或用户特定信息。 |
DelimiterCharacters |
指示扩展器将用于对文本框的内容进行标记的一个或多个字符。Web 服务随后将使用***一个标记来提供建议。默认情况下不设置此属性。 |
EnableCaching |
一个布尔属性,用于指示是否启用客户端缓存。默认情况下为 True。 |
FirstRowSelected |
一个布尔属性,用于指示是否自动选择列表中的***个选项。默认情况下为 False。 |
MinimumPrefixLength |
获取并设置文本框缓冲区中可触发绑定的 Web 服务的最少字符数。默认值为 3。 |
ServiceMethod |
获取并设置用于调用绑定的 Web 服务的方法名称。 |
ServicePath |
获取并设置绑定的 Web 服务的 URL。 |
UseContextKey |
一个布尔属性,用于指示在指定了 ContextKey 属性的情况下是否应使用该属性的值。默认情况下为 False。 |
#p#
构建自动完成 Web 服务
与 AutoComplete 扩展器组合使用的 Web 服务是一项 ASP.NET AJAX 脚本服务。该服务看起来几乎与常规的 ASP.NET Web 服务没什么两样,只是该服务的类必须用 ScriptService 属性加以修饰。如果您使用的 Web 服务缺少该属性,则对相关 ASMX 端点的每个请求都会导致 HTTP 500 错误。不会向最终用户显示异常界面(扩展器总是妥善地进行降级处理),而且也不会显示带有建议的弹出面板:
[ScriptService] |
请注意,脚本服务不需要 WebService 属性,但仍可使用该属性来提供命名空间信息。
脚本服务类上使用 WebMethod 属性标记的任何公共方法的名称都可以成功地分配给扩展器上的 ServiceMethod 属性。用于提供建议的方法必须具有以下签名:
[WebMethod] |
***个参数是用于生成建议的前缀文本。它与文本框的当前内容相同,其长度不小于 MinimumPrefixLength 属性的值。Count 参数指示要提供的建议数。Count 参数的值来自 CompletionSetCount 属性的值。
如果计划利用上下文关键字(一个字符串属性,用于指示要传递给绑定的 Web 服务的任何页面或用户特定的信息),则应为要使用的任何 Web 服务方法提供重写方法。下面是签名:
public string[]GetSuggestions( |
返回值始终以字符串数组形式打包。由于使用了 ScriptService 属性,因此服务器与客户端之间的所有通信都将通过 JavaScript Object Notation (JSON) 字符串进行。
可以利用 Web 服务方法上支持的任何属性来改善服务性能。例如,WebMethod 属性上的 CacheDuration 属性可以强制服务对指定期间内方法调用的响应进行缓存。同样,如果方法的逻辑确实需要会话状态,则您可以启用会话状态。
图 4 显示了针对客户名称提供建议的示例服务,客户名称来自 Northwind 数据库。从性能角度来说,键入少量字符就调用 Web 服务可能听起来并不是一个好主意。但是,有一些因素使得自动完成比您想像的要更实用。AutoComplete 扩展器的客户端缓存基于本地内存,永远不会通过隐藏字段保持。通过使用指定前缀作为关键字,可以将与该前缀关联的完成列表存储到内部数组中。只要在文本框缓冲区中分解出相同的前缀,都会检索该列表。因此,如果用户重复键入相同的前缀,则不会通过网络对后端服务执行任何新的请求。
Figure4建议服务示例
using System; using System.Web; using System.Web.Services; using System.Web.Services.Protocols; using System.Data; using System.Data.SqlClient; using System.Web.Script.Services; [WebService(Namespace = "MsdnMag.Articles")] [ScriptService] public class SuggestionService : System.Web.Services.WebService { [WebMethod] public string[] GetSuggestions(string prefixText, int count) { DataView data = GetData(); data = FilterData(data, prefixText); int totalCount = data.Count; if (data.Count > count) totalCount = count; string[] suggestions = new string[totalCount]; int i = 0; foreach (DataRowView row in data) { suggestions[i++] = (string) row["companyname"]; if (i >= count) break; } return suggestions; } private DataView GetData() { DataView view = (DataView)HttpContext.Current.Cache["Suggestions"]; if (view == null) { SqlDataAdapter adapter = new SqlDataAdapter( "SELECT * FROM customers", "..."); DataTable table = new DataTable(); adapter.Fill(table); view = table.DefaultView; HttpContext.Current.Cache["Suggestions"] = view; } return view; } private DataView FilterData(DataView view, string prefix) { view.RowFilter = String.Format("companyname LIKE '{0}%'", prefix); return view; } }
客户端缓存明显比服务器端缓存更有效,服务器端缓存可减少一些与数据库之间的往返过程,但无法减少与 Web 服务器之间的往返行程。在图 4 显示的代码中,服务加载数据库中的所有客户并在 ASP.NET 缓存中存储该列表。然后,从缓存中检索客户列表并筛选出与前缀匹配的名称。
如前所述,用于提供建议的 Web 服务必须是 ASP.NET AJAX 脚本服务,并通过 JSON 与客户端进行通信。您需要确定 SOAP 客户端是否也可公开访问该服务。ASP.NET AJAX 服务默认情况下具有双重功能:JSON 和 SOAP。通过将以下代码添加到主机应用程序的 web.config 文件,可以关闭 SOAP 客户端:
<system.web> |
使用 ASP.NET 3.5,还可以通过服务 (SVC) 端点将 AutoComplete 扩展器绑定到 Windows® Communication Foundation (WCF) 服务。该扩展器使用以下 JavaScript 代码来代替调用:
Sys.Net.WebServiceProxy.invoke( |
对于 Microsoft AJAX 客户端库中的 WebServiceProxy 类,关键是指定端点在内容类型请求标题设置为“application/json; charset=utf-8”时可以成功处理请求。若要创建 WCF 服务来提供建议,需要与下面类似的类:
[ServiceContract(Namespace = "MsdnMag.Services")] |
此外,还需要一个 SVC 端点,如下所示:
<%@ ServiceHost Language="C#" |
若要注册服务,可以使用 webHttpBinding 绑定模型向 web.config 文件的 serviceModel 部分添加显式端点。或者,可以指定 @ServiceHost 指令的 Factory 属性,并使该属性指向以下类:
System.ServiceModel.Activation.WebScriptServiceHostFactory |
#p#
设置 AutoComplete 扩展器的样式
AutoComplete 扩展器支持相关样式设置属性,通过这些属性,您可以指定要对控件的样式部分使用的 CSS 类。特别是,可以设置整个弹出区域的样式,包括边框和背景色。还可以对所有项和所选项使用不同设置。没有为可选项提供任何预定义样式。默认情况下,不会选择完成下拉列表中的***个元素。但是,可以使用 FirstRowSelected 属性强制自动选择***项。
完成列表将在经过指定毫秒数后显示。经过的时间通过 CompletionInterval 属性来控制,默认情况下设置为一秒。经过指定的时间后,扩展器将调用服务以获取建议列表。
可以使用 Animations 属性向列表的打开过程添加动作。可以对以下两个事件定义动画:OnShow 和 OnHide。动画通过 Animation 扩展器及其相关框架来执行(参见图 5 中的示例)。
Figure5使用 Animations 属性
<Animations> |
动画脚本会向完成列表添加淡入和淡出效果。OpacityAction 节点用于设置透明度,HideAction 节点用于显示完成列表以及任何其他视觉效果。***,FadeIn 和 FadeOut 动作执行淡化效果。图 6 显示了一个动态完成列表。
对列表进行渐进式搜索
是否曾尝试在长长的列表中查找某个特定项,例如,在包含世界上所有国家/地区的列表中查找某个国家/地区的名称?如果您速度足够快地键入一些连续字母,可能会找到所需的国家/地区,但是即使犹豫了几毫秒,那么键入的下一个字母就会成为搜索项的***个字母。ListSearch 扩展器解决了这一限制。请注意,该扩展器仅适用于 ASP.NET Web 和 HTML 控件,不可与 SELECT 或 OPTION 等常规 HTML 元素一起使用。
因此,ListSearch 扩展器的主要优点是:它允许您通过键入字母来搜索列表控件中的项,并防止搜索字符串在几秒钟后丢失;相反,搜索字符串在您按 Esc 或回发至服务器(包括全部或部分回发)之前将一直保留在原处。键入的任何其他字符都将附加到搜索字符串,用于进一步缩小搜索范围。以下介绍如何使用 ListSearch 扩展器:
<act:ListSearchExtender ID="ListSearchExtender1" runat="server" |
该扩展器提供了三个主要属性:PromptText、PromptCssClass 和 PromptPosition。所有这些属性都与提示文本有关,提示文本是显示在目标控件周围的字符串,用于提供有关正在搜索的文本的可视化反馈。PromptText 的默认值为“Type to search”。当目标列表控件获得焦点后,此文本通常显示在该控件的上方。PromptCssClass 属性获取并设置要应用于提示消息的 CSS 类的名称。提示文本由用户键入的搜索文本来取代。Esc 和 Del 按钮在此处起着重要作用。Esc 按钮用于清除当前搜索并将列表重置为默认所选项。Del 按钮用于从搜索文本中删除上一次键入的字符,并在列表中更新选择项。此外,Animations 属性的作用与上文 AutoComplete 扩展器部分中讨论的作用相同。
#p#
弹出式上下文菜单
在用户即将执行操作时,为他们提供可以执行哪些操作的选项,这一点非常好。几年前,工具提示就是一项巨大的改进,因为它们提供了有关特定控件角色的弹出式附加信息。动态 HTML 的出现使得 HTML 工具提示成为可能。
如今,HoverMenu 扩展器能够在任意 ASP.NET 服务器控件旁边显示弹出面板。此扩展器最常用的一个用法是,显示由鼠标移动事件而不是右键单击激活的上下文菜单。
当用户将鼠标移动到控件上方时,HoverMenu 扩展器就会激活。因此,将在控件附近显示指定的弹出面板;实际位置可以通过编程方式进行控制。此外,可以对控件应用 CSS 样式以醒目的格式标记该控件。
图 7 显示的单选按钮菜单可提供有关要在文本框中插入的文本的建议。下面是相关扩展器的声明:
<act:HoverMenuExtender ID="HoverMenu1" runat="server" |
Panel1 控件包含单选按钮列表。为了确保所有选择都在文本框目标控件中进行处理,您在单选按钮列表中定义了一个 SelectedIndexChanged 事件,并将所有相关操作都封装在 UpdatePanel 控件中。(有关详细信息,请参阅本专栏的下载内容中所附的源代码)。
除了 PopupControlID 和 TargetControlID 属性之外,HoverMenu 扩展器还提供了一些其他属性。HoverCssClass 属性指示要在悬停菜单可见时应用于目标控件的 CSS 类。PopupPosition 属性指示相对于目标控件的弹出位置,可能的值包括 Top、Right、Left 和 Bottom。OffsetX 和 OffsetY 属性用于设置相对于确定位置的水平和垂直偏移量。***,PopDelay 属性指示 DOM 事件与显示弹出菜单之间的延迟。默认值为 100 毫秒。
将鼠标悬停在 DOM 事件上方时,该事件会触发 HoverMenu 扩展器。HoverMenu 扩展器与 Popup 扩展器之间并没有太大差异。主要区别在于激活机制和触发器。当用户将焦点指向特定的目标控件时,将会激活 Popup 扩展器。若要激活 HoverMenu 扩展器,用户只需将鼠标移动到相应控件上方即可。
结束语
如果希望网站内容更为丰富并具有更强的交互性,则就需要使用更多的 JavaScript。虽然手工编写 JavaScript 在实现简单功能方面尚能够胜任,但是,如果要实现更高层次的交互性,仅靠手工编写代码是远远不够的。
【编辑推荐】