控件的实现
contextmenu控件的核心在于重写createchildcontrols方法。在这个方法中控件创建界面并在页面中写入所需的脚本。我们说过,contexmenu控件的用户界面分为两部分——图形和脚本。我们先说图形。
createchildcontrols方法产生一个可以在页面移动的html块,它就是所需的弹出菜单。照这样看来,快捷菜单就是包含一个table表单的<div> ,每一个菜单项就是这个table表单中的一行。使用table是由于一系列的开发点(象边框和浮动层)和它能很容易的扩展(例如添加侧边图象)所决定的。
htmlgenericcontrol div = new htmlgenericcontrol("div");
div.id = "root";
div.style["display"] = "none";
div.style["position"] = "absolute";
if (autohide)
div.attributes["onmouseleave"] = "this.style.display=’none’";
我们使用层叠样式表(css)来隐藏最外层的<div>标签,并且用绝对位置标记这个<div>。如果自动隐藏可用,那么<div> 还得处理 mouse-leave(鼠标离开)事件来隐藏本身。那么 onmouseout和onmouseleave事件有什么不同呢?前者是当鼠标移动到一个新的元素上时发生,而后者是当鼠标移出绑定对象时发生。举例说明:你的鼠标在一个有两行的表单(table)上移动。当你在table的两行之间移动时,onmouseout事件就会发生;只有你的鼠标移动到table表单之外时onmouseleave事件才发生。
table包含和要显示的菜单项个数相同的行,每一行有一个单元格,每个单元格里放一个linkbutton对象。菜单通过一个循环创建:
foreach(contextmenuitem item in contextmenuitems)
{
tablerow menuitem = new tablerow();
menutable.rows.add(menuitem);
tablecell container = new tablecell();
menuitem.cells.add(container);
linkbutton button = new linkbutton();
container.controls.add(button);
...
}
行的单元格有一组脚本操作——onmouseover和onmouseout——完成鼠标划过的效果。当鼠标划过时改变背景颜色。鼠标离开时恢复初始颜色。默认的背景色由从webcontrol继承的background属性指定。高亮颜色由新的属性rollovercolor指定。
string color = string.format(contextmenu.onmouseover, colortranslator.tohtml(rollovercolor));
container.attributes["onmouseover"] = color;
color = string.format(contextmenu.onmouseout, colortranslator.tohtml(backcolor));
container.attributes["onmouseout"] = color;
你需要把.net的system.drawing.color值转换成可用的html颜色。有意思的是,无论是color类的tostring方法还是它的name属性都不能在所有情况下返回对应的html颜色字符串,不知是不是有意这样的:(。name属性基本可以实现这一功能,只有和种情况例外。当颜色不能和已知的颜色匹配时,这个属性返回颜色的rgb组,外加alpha通道值。要得到当前的html颜色,你必须移除alpha通道值(通常是开头的十六进制 ff 字符串)并使用#号替换它。幸运的是,system.drawing.colortranslator类可以自动完成这项工作:)。
我们接着要对链接按钮做一些调整,以使其正常工作。 也就是:把链接的宽度设成100%以确保当没有其它设置时,在整个行上光标都是手状。 同样的,要设置从对应的菜单项对象得到的文本(text),工具提示(tooltip),和命令名(command name)。最后为点击事件关联一个处理器。
linkbutton button = new linkbutton();
container.controls.add(button);
button.click += new eventhandler(buttonclicked);
button.width = unit.percentage(100);
button.tooltip = item.tooltip;
button.text = item.text;
button.commandname = item.commandname;
回传时,事件源被识别为在contextmenu命名容器内的linkbutton,并且得到处理回传事件的时机。点击事件的内部处理器将所有信息打包进一个新的itemcommand 事件并引激活这个事件,参见下面的代码
private void buttonclicked(object sender, eventargs e)
{
linkbutton button = sender as linkbutton;
if (button != null)
{
commandeventargs args = new commandeventargs( button.commandname, button.commandargument);
onitemcommand(args);
}
}
protected virtual void onitemcommand(commandeventargs e)
{
if (itemcommand != null)
itemcommand(this, e);
}
页面上的代码将获得两部分内容:引发事件的contextmenu实例;与点击项相关的command name。
这时,table就是快捷菜单的用户界面。它一开始被放置在页面的任意位置,并且使用css样式表在视图中隐藏。在用户右击时,这段html代码块(使用绝对位置方式定位)将被显示成一个快捷菜单。javascript代码负责截取事件并把菜单移动动所需位置,参见如下代码:
<script language="javascript">
function __showcontextmenu(menu)
{
var menuoffset = 2 menu.style.left = window.event.x - menuoffset;
menu.style.top = window.event.y - menuoffset;
menu.style.display = "";
window.event.cancelbubble = true; return false;
}
function __trapesc(menu)
{
var key = window.event.keycode;
if (key == 27)
{
menu.style.display = ’none’;
}
}
</script>
__showcontextmenu函数设置快捷菜单对象的top和left属性,以使它在点击发生的位置显示。少量的偏移是确保当快捷菜单显示时,鼠标已经处于它的上面。这样也防止由于鼠标在菜单边缘的轻微移动而使菜单自动隐藏。鼠标事件的冒泡也必须被停止,这样在文档对象模型层次中高层的结点就不会捕获右击事件。
那么由谁来调用__showcontextmenu函数呢?答案是:浏览器。当浏览检测到有和html元素的oncontextmenu事件相关联的函数时,它会调用这个函数。我们以前说过oncontextmenu事件是inte.net explorer特有的事件.netscape浏览器不支持此事件。作为代替可以使用onmouseup事件来检测和处理松开鼠标右键的事件。
快捷菜单也负责为每个控件或为注册快捷菜单的页面元素添加oncontextmenu事件处理器。我定义了两种方式使一个元素获取它的快捷菜单.boundcontrols集合属性是一个数组。它由需要使用该快捷菜单的所有页面控件填充,并且完成填充的代码写在页面代码中.如下:
void page_load(object sender, eventargs e)
{
contextmenu1.boundcontrols.add(button1);
...
}
以上代码产生如下标记:
<input type=submit ... oncontextmenu="__showcontextmenu(...)" />
当用户在控件上右击时会弹出快捷菜单。这种方法要求任何使用自定义快捷菜单的元素必须是服务器控件,有时这种要求是不合适的。例如:假使你想为一个图片使用自定义的快捷菜单。你必须把图片标记<img>写成 runat=server。其实没必要这样。看下面的例子:
<img oncontextmenu="<% = contextmenu1.getmenureference() %>" src="...">
getmenureference方法返回一段用于调出快捷菜单的脚本。这样页面元素不需要定义成服务器控件也能具有所需的快捷菜单
Java Asp PHP .Net XML C/C++ CGI VB Jsp J2ee J2se J2me EJB Servlet Tomcat Resin Struts Weblogic Eclipse ANT GUI JMS Web servise IDEA Webphere Hibernate Spring Jboss Applet Swing Socket Javamail Perl Ajax P2P 安全 模式 框架 测试 开源 游戏
Windows XP Windows 2000 Windows 2003 Windows Me Windows 9.x Linux UNIX 注册表 操作系统 服务器 应用服务器