為ASP.NET控件加入快捷菜單
雖然快捷菜單在桌面應(yīng)用程序中已經(jīng)是非常通用的元素,但是由于在象ASP.NET這樣的基于服務(wù)器的技術(shù)沒(méi)有很好的描繪,所以在Web應(yīng)用程序中快捷菜單并不是很通用。要想使用快捷菜單,瀏覽器必須高度支持DHTML和豐富事件模式,例如:Microsoft Internet Explorer 5.0及更高版本,或者Netscape 6.0等。然而,各種瀏覽器的對(duì)象模式雖然功能上大至相同,但是成員各名字卻各不相同,這就需要我們自己實(shí)現(xiàn)對(duì)象和事件的從一種模式到到另一種模式的轉(zhuǎn)換。
這里,我們創(chuàng)建一個(gè)針到Internet Explorer的對(duì)象模式的ASP.NET快捷菜單。接著,我將經(jīng)過(guò)修改使其功能支持其它瀏覽器。
ContextMenu Control 快捷菜單控件概述:
MSDN Liabrary中包含了幾個(gè)DHTML快捷菜單的示例。分別提供了對(duì)這一功能的不能實(shí)現(xiàn)方法。一個(gè)快捷菜單就是在頁(yè)面中任何位置的一組標(biāo)記代碼。它包括兩部分內(nèi)容——界面和腳本(當(dāng)用戶(hù)在頁(yè)面右擊時(shí)關(guān)聯(lián)UI),UI提供一個(gè)可點(diǎn)擊的元素的列表——菜單項(xiàng)——和各自的內(nèi)容文本,圖標(biāo),命令名(command name),目標(biāo)url,提示(tooltip),和所有你認(rèn)為有必要顯示出來(lái)的東西??旖莶藛谓缑媸琼?yè)面的一部分,并且屬于頁(yè)面控件樹(shù)中的一員。(太多的快捷菜單將會(huì)出現(xiàn)執(zhí)行的問(wèn)題:與大多數(shù)用戶(hù)的常規(guī)情況相比,ASP.NET將發(fā)送更多的快捷菜單到瀏覽器)當(dāng)用戶(hù)在頁(yè)面的一個(gè)元素上右擊時(shí),將引發(fā)一段JavaScript,這段腳本將快捷菜單移動(dòng)到右擊的位置顯示。
快捷菜單將保持隱藏屬性,只有當(dāng)用戶(hù)在頁(yè)面的一個(gè)綁定個(gè)快捷菜單的元素上右擊時(shí),快捷菜單才顯示。頁(yè)面元素接收腳本事件并彈出一個(gè)快捷菜單作為響應(yīng)。腳本事件信賴(lài)于瀏覽器,在Internet Explorer 5.0和更新版本中是 OnContexMenu事件.在Netscape6.0和更新版本中你要使用 OnMouseUp 事件(在Internet Explorer 5.0+中你也可能使用OnMouseUp事件,但要多寫(xiě)幾行代碼)在接收事件的腳本中,獲取快捷菜單的UI代碼塊并且將它移動(dòng)到發(fā)生點(diǎn)擊的位置。同時(shí)設(shè)置彈出的panel的 visibilty屬性。當(dāng)用戶(hù)在菜單項(xiàng)上點(diǎn)擊時(shí),頁(yè)面回傳并引發(fā)服務(wù)器端事件。對(duì)于服務(wù)器而言,點(diǎn)擊一個(gè)菜單項(xiàng)和點(diǎn)擊一具常規(guī)的按鈕沒(méi)什么區(qū)別。
當(dāng)用戶(hù)戶(hù)想取消已經(jīng)打開(kāi)的快捷菜單時(shí)怎么辦呢?在windows程序中,按下Esc鍵或者在菜單區(qū)域外點(diǎn)擊都可以取消已彈出的快捷菜單。所以你必須在Web中實(shí)現(xiàn)這一功能。請(qǐng)注意,只有快捷菜單處于活動(dòng)(顯示出來(lái))時(shí),Esc鍵才有郊。因?yàn)镋sc還可用于其它元素的其它鍵盤(pán)快捷方式。
我還可以讓菜單在用戶(hù)鼠標(biāo)移開(kāi)菜單時(shí)隱藏??梢酝ㄟ^(guò)腳本操作OnMouseLeave 事件實(shí)現(xiàn)。
使用彈出菜單控件
假定我們已以設(shè)計(jì)出了這個(gè)彈出菜單(我們一會(huì)兒再說(shuō)如何實(shí)現(xiàn)這個(gè)快捷菜單控件),那么如何使用它在ASP.NET頁(yè)面中添加一個(gè)或多個(gè)快捷菜單呢?首先,在Visual Studio? .NET的工個(gè)欄中拖一個(gè)或多個(gè)快捷菜單控件到頁(yè)面上。然后,為每個(gè)菜單添加菜單項(xiàng),并配置每個(gè)菜單項(xiàng)的的工具提示,命令名(command name)和其它所需的內(nèi)容,例如快捷鍵和幫助主題的鏈接。命令名(command name)用于在響應(yīng)點(diǎn)擊快捷菜單發(fā)生頁(yè)面回傳時(shí)確定是哪一個(gè)菜單項(xiàng)被點(diǎn)擊;對(duì)每一個(gè)快捷菜單控件實(shí)例的菜單項(xiàng)集合它必須是唯一的。
你必須在HTML標(biāo)簽的OnContextMenu事件中加入代碼來(lái)彈出快捷菜單,代碼必須信賴(lài)一系列的參數(shù),象點(diǎn)擊的x,y坐標(biāo),點(diǎn)擊的元素,和要使用的快捷菜單的實(shí)例等。注意:如果必要你可以使用這種方式完全代替瀏覽器的快捷菜單。綁定到OnContextMenu事件執(zhí)行的JavaScript代碼是在運(yùn)行時(shí)動(dòng)態(tài)生成的。ContextMenu控件將暴露一個(gè)集合屬性來(lái)包含分綁定快捷菜單的控件集合,在ContextMenu控件將在運(yùn)行時(shí)給這些要綁定的控件一個(gè) oncontextmenu 屬性。OK!完成!可以測(cè)試了。
慢著,讓我們先來(lái)想一下ContexMenu控件和頁(yè)中任意的顯示快捷菜單的元素的綁定機(jī)制,這種機(jī)制對(duì)設(shè)計(jì)時(shí)的支持怎么樣?理想的情況是:根據(jù)基類(lèi)每一個(gè)Web控件直接暴露一個(gè) ContextMenuId屬性。然后在屬性窗口中選擇這個(gè)屬性時(shí),將看到在頁(yè)面中的ContextMenu控件的列表。當(dāng)然這些ContextMenu控件我們是已經(jīng)創(chuàng)建了的;ContextMenuId屬性在ASP.NET 1.x中不支持,在將來(lái)的ASP.NET2.0中也不支持。
在Visual Studio .NET 2003 集成開(kāi)發(fā)環(huán)境中,ASP.NET復(fù)合控件可以很好的完成這一工作。可以通過(guò)使用類(lèi)撰寫(xiě)組合現(xiàn)有控件來(lái)創(chuàng)作新控件。復(fù)合控件可呈現(xiàn)一個(gè)重新使用現(xiàn)有控件功能的用戶(hù)界面。復(fù)合控件可以從子控件的屬性合成屬性并處理由子控件引發(fā)的事件。它還可以公開(kāi)自定義屬性和事件。
我不選擇使用復(fù)合控件有以下幾個(gè)原因:一個(gè)是Visual Studio .NET 2003對(duì)于Web窗體中的控件功能的擴(kuò)展支持的不好(請(qǐng)參見(jiàn):Extender provider components in ASP.NET: an IExtenderProvider implementation),第二,在Visual Studio 2005的ASP.NET設(shè)計(jì)器中不再支持組件托盤(pán)區(qū)。Web窗體設(shè)計(jì)器現(xiàn)在僅支持ASP.NET控件而忽略象復(fù)合控件這樣的非可視化的組件。Visual Studio 2005將不再信賴(lài)InitializeComponent節(jié),并且不再在代碼文件中自動(dòng)添任何工具生成(tool-generated)的代碼。ASP.NET控件也不設(shè)計(jì)成具有快捷菜單,所以要綁定快捷菜單只能通過(guò)快捷菜單控件自身的執(zhí)行。這里我使用類(lèi)似ASP.NET驗(yàn)證控件和被驗(yàn)證控件之間關(guān)聯(lián)的形式。
【編輯推薦】