虽然快捷菜单在桌面应用程序中已经是非常通用的元素,但是由于在象asp.NET这样的基于服务器的技术没有很好的描绘,所以在Web应用程序中快捷菜单并不是很通用.要想使用快捷菜单,浏览器必须高度支持DHTML和丰富事件模式,例如:Microsoft Internet Explorer 5.0及更高版本,或者Netscape 6.0等.然而,各种浏览器的对象模式虽然功能上大至相同,但是成员各名字却各不相同,这就需要我们自己实现对象和事件的从一种模式到到另一种模式的转换.
这里,我们创建一个针到Internet Explorer的对象模式的asp.NET快捷菜单.接着,我将经过修改使其功能支持其它浏览器.代码支持asp.NET 1.x,也可以在asp.NET2.0 Beta1下编译通过 Outline of the
ContextMenu Control 快捷菜单控件概述: MSDN Liabrary 中包含了几个DHTML快捷菜单的示例.分别提供了对这一功能的不能实现方法.一个快捷菜单就是在页面中任何位置的一组标记代码.它包括两部分内容——界面和脚本(当用户在页面右击时关联UI),UI提供一个可点击的元素的列表——菜单项——和各自的内容文本,图标,命令名( command name ),目标url,提示( tooltip ),和所有你认为有必要显示出来的东西.快捷菜单界面是页面的一部分,并且属于页面控件树中的一员.(太多的快捷菜单将会出现执行的问题:与大多数用户的常规情况相比,asp.NET将发送更多的快捷菜单到浏览器)当用户在页面的一个元素上右击时,将引发一段JavaScript,这段脚本将快捷菜单移动到右击的位置显示. 快捷菜单将保持隐藏属性,只有当用户在页面的一个绑定个快捷菜单的元素上右击时,快捷菜单才显示.页面元素接收脚本事件并弹出一个快捷菜单作为响应.脚本事件信赖于浏览器,在Internet Explorer 5.0和更新版本中是 OnContexMenu事件.在Netscape6.0和更新版本中你要使用 OnMouseUp 事件( 在Internet Explorer 5.0+中你也可能使用OnMouseUp事件,但要多写几行代码 )在接收事件的脚本中,获取快捷菜单的UI代码块并且将它移动到发生点击的位置.同时设置弹出的panel的 visibilty属性.当用户在菜单项上点击时,页面回传并引发服务器端事件.对于服务器而言,点击一个菜单项和点击一具常规的按钮没什么区别. 当用户户想取消已经打开的快捷菜单时怎么办呢?在windows程序中,按下Esc键或者在菜单区域外点击都可以取消已弹出的快捷菜单.所以你必须在Web中实现这一功能.请注意,只有快捷菜单处于活动(显示出来)时,Esc键才有郊.因为Esc还可用于其它元素的其它键盘快捷方式. 我还可以让菜单在用户鼠标移开菜单时隐藏.可以通过脚本操作 OnMouseLeave 事件实现. 使用弹出菜单控件 假定我们已以设计出了这个弹出菜单(我们一会儿再说如何实现这个快捷菜单控件),那么如何使用它在asp.NET页面中添加一个或多个快捷菜单呢?首先,在Visual Studio? .NET的工个栏中拖一个或多个快捷菜单控件到页面上.然后,为每个菜单添加菜单项,并配置每个菜单项的的工具提示,命令名(command name)和其它所需的内容,例如快捷键和帮助主题的链接.命令名(command name)用于在响应点击快捷菜单发生页面回传时确定是哪一个菜单项被点击;对每一个快捷菜单控件实例的菜单项集合它必须是唯一的. 你必须在HTML标签的OnContextMenu事件中加入代码来弹出快捷菜单,代码必须信赖一系列的参数,象点击的x,y坐标,点击的元素,和要使用的快捷菜单的实例等.注意:如果必要你可以使用这种方式完全代替浏览器的快捷菜单.绑定到OnContextMenu事件执行的JavaScript代码是在运行时动态生成的.ContextMenu控件将暴露一个集合属性来包含分绑定快捷菜单的控件集合,在ContextMenu控件将在运行时给这些要绑定的控件一个 oncontextmenu 属性.OK!完成!可以测试了. 慢着,让我们先来想一下ContexMenu控件和页中任意的显示快捷菜单的元素的绑定机制,这种机制对设计时的支持怎么样?理想的情况是:根据基类每一个Web控件直接暴露一个 ContextMenuId属性.然后在属性窗口中选择这个属性时,将看到在页面中的ContextMenu控件的列表.当然这些ContextMenu控件我们是已经创建了的;ContextMenuId属性在asp.NET 1.x中不支持,在将来的asp.NET2.0中也不支持. 在Visual Studio .NET 2003 集成开发环境中,asp.NET复合控件可以很好的完成这一工作.可以通过使用类撰写组合现有控件来创作新控件.复合控件可呈现一个重新使用现有控件功能的用户界面.复合控件可以从子控件的属性合成属性并处理由子控件引发的事件.它还可以公开自定义属性和事件. 我不选择使用复合控件有以下几个原因:一个是Visual Studio .NET 2003对于Web窗体中的控件功能的扩展支持的不好,第二,在Visual Studio 2005的asp.NET设计器中不再支持组件托盘区.Web窗体设计器现在仅支持asp.NET控件而忽略象复合控件这样的非可视化的组件.Visual Studio 2005将不再信赖InitializeComponent节,并且不再在代码文件中自动添任何工具生成(tool-generated)的代码.asp.NET控件也不设计成具有快捷菜单,所以要绑定快捷菜单只能通过快捷菜单控件自身的执行.这里我使用类似asp.NET验证控件和被验证控件之间关联的形式.
编程接口 我们的ContextMenu控件从WebControl继承并执行INamingContainer接口 public class ContextMenu : WebControl, INamingContainer 图一控件的成员细节,如下:
属性
描述
AutoHide
标志当用户鼠标移出控件区域时,是否自动隐藏快捷菜单
BoundControls
返回使用快捷菜单的控件集合
CellPadding
返回或设置每个菜单项周围的空间的象素数
ContextMenuItems
返回菜单项的集合
RolloverColor
返回或设置当鼠标划过菜单项时突显的颜色
方法
描述
GetEscReference
返回当用户按下Esc键时用于隐藏页面中的快捷菜单的JavaScrip代码
GetMenuReference
返回一段JavaScript代码,这段代码将关联到快捷菜单所对应的HTML元素上.
GetOnClickReference
返回当用户在菜单区域外点击时隐藏快捷菜单的代码.
事件
描述
ItemCommand
当用户点击一个快捷菜单项进激发. 关键属性是ContextMenuItmes集合属性,它包含了ContextMenuItem类型的对象集合,每一个对象表示一个菜单项.ContextMenuItem类的源码如下:
[TypeConverter( typeof( ExpandableObjectConverter ) )] public class ContextMenuItem
{
public ContextMenuItem( )
{
}
public ContextMenuItem( string text, string commandName )
{
_text = text;
_commandName = commandName;
}
private string _text;
private string _commandName;
private string _tooltip;
public string Text
{
get
{
return _text;
}
set
{
_text = value;
}
}
public string CommandName
{
get
{
return _commandName;
}
set
{
_commandName = value;
}
}
public String Tooltip
{
get
{
return _tooltip;
}
set
{
_tooltip = value;
}
}
}
每个菜单项具有显示文本,命令名( command name ),提示文本( tooltip ).你可以通过各方法扩展这个类,例如添加一个图片URL,一个不可用状态,或一个目标URL等.显示文本被显示于菜单项上;命令名是一个唯一标识字符串,用于指定或确定与菜单项关联的命令.tooltip获取或设置当鼠标指针停留在菜单项上时显示的工具提示文本 当用户点击菜单项时,页面回传并激发一个服务器端的ItemCommand事件.控制页通过操作这一事件来执行一些代码来响应用户对菜单项的点击.图3是一个使用快捷菜单的示例工程的截图:
要使用快捷菜单,你需要使用menu item对象填充ContextMenuItems集合,调整一些可视化样式,至少添加一个控件到BoundControls集合中.然后在浏览器中打开示例页,在任意绑定快捷菜单的控件上右击.效果如图:
每个菜单项包含一个LinkButton控件,这个LinkButton控件有一个内部绑定的点击事件处理程序.当检测到点击时,页面回传并激发这个点击事件.接着,预定义的处理程序将事件冒泡到上一级,并改名为ItemCommand. 控件还定义了一些可视化的属性,象CellPadding,RolloverColor和AutoHide.重申一下,在Windows中快捷菜单可以在按下Esc键或在菜单区域外点击时取消.对于基于Web的快捷菜单来说,AutoHide属性为快捷菜单的根标签添加OnMouseLeave脚本,所以当用户的鼠标离开菜单区域时,这个根标签的子树将隐藏.把AutoHide作为一个可设置的属性,用户可以在需要的时候设置是否在鼠标离开时自动隐藏快捷菜单. 要使菜单能够在点击或按Esc键时隐藏,需要添加如下处理程序:< br>
<bodyonkeypress="..."onclick="..."> 处理程序脚本可以被程序化的添加到每一个页面元素,只要这个元素被标记为runat=server.这样实际上就是在ContextMenu快捷菜单控件和页面之间创建了一个逻辑信赖.另外,你必须在页面上定义一个额外的服务器控件.当然,在运行时实例化一个额外的控件并不会严重的影响执行效果,但是为什么仅仅因为想容易的consume其它的控件而实例化一个无用的控件呢.作为选择下面这个方法也可以达到同样的效果:用body获取按Esc键和鼠标点击,并且你节省了服务器控件的开支
<body onkeypress="<% = ContextMenu1.GetEscReference( ) %>" onclick="<% = ContextMenu1.GetOnClickReference( ) %>"> 让我们更详细的说一下控件的实现