在我主持過的一個Asp.Net論壇上,一個使用者詢問如何在一個頁面上去通過hyperlink列出一個路徑下的很多檔案名,能使使用者能點選它們。我認為這是可能是經常執行的動作,是以決定建立一個伺服器控件來封裝它。
起初,我嘗試了Web使用者控件,但我想能允許設定邊框,字型,背景顔色等。使用Web使用者控件,我要為每一個屬性手動設定。俗話說:“你寫的代碼越少,你的錯誤越少了”,是以我要研究一個更好的方法。
我決定建立自己首個自定義伺服器控件。我試着去繼承一個label控件,但label控件不支援滾動條。 是以,我選擇繼承Panel控件。最終的控件具有Panel控件的所有屬性(顔色,邊框,滾動支援等),再加上一些我添加自定義屬性。使用Panel控件将會盡最小的努力。
第一部分:自定義伺服器控件
初始化的伺服器控制相對容易。下面是最終的代碼:
代碼
注意:
控件名字:
去煩惱一個控件的名稱是非常愚蠢做法,真的是這樣嗎?錯誤的命名一個控件(或裡任何變量)就像結婚。由于你将要與它走很長一段時間,在将來改變它可能會非常痛苦。是以首先要用好你的命名。
我稱這個控件為: HyperlinkFileList.
溢出問題:
如果控件的高度一旦設定,檔案的清單超出了控件的高度。就會使檔案“溢出”控件的邊界。
為了解決這個問題,我将下面代碼放到控件的構造函數之中:
if ((Height != null) && (ScrollBars == ScrollBars.None))
ScrollBars = ScrollBars.Auto;
CSS 布局:
因為控件是基本是一個div(panel渲染成一個div),然後,設定"display"屬性為"inline-block",允許多個控件并排在一起。
Style["display"] = "inline-block";
CSS框模型:
我不喜歡文本卡在控件的左側,是以我添加一些CSS來填充。我也在控件的周圍使用一些css樣式。使它不會與其它控件貼的很死。
// add spacing outside the control
Style["margin"] = "0.5em";
// add space inside the control
Style["padding-left"] = "0.5em";
狀态管理:
在最初的測試的時候, 我發現每次控件都能運作,它都将重新讀取的檔案目錄。檔案輸入輸出代價是很昂貴的。我想去結合的伺服器控件的“State”。但它使用的是View State 類型,兩次發送檔案清單到用戶端是效率非常低的 。一次作為HTML清單,一次在ViewState 。
是以我想使用 Session State, Application State 和Cache。
我決定将檔案清單放在一個緩存對象之中。使清單能在session之間共享。如果記憶體在溢出,緩存中的清單将會丢失。
我将檔案的目錄和檔案filter連接配接在一起,作為緩存中索引鍵。這樣允許多個控件同時使用和共享檔案清單。
開始,我添加了使開發人員可以強制重新讀取需要的檔案的功能。但是,緩存對象可以使用依賴關系:任何從屬目錄更改會導緻緩存過期。最後的代碼是非常的簡單:
側注:當然,這隻是一個代碼行,但做了幾個小時的研究,以決定這是最好的方法去處理狀态的管理的問題。有時需要很長的時間編寫很少的代碼。
Property Editor:
我将所有的自定義屬性分組到标題 "Files List"下面。他們都在一個地方與Panel的屬性分離開來。
下面是四個控件在一個頁面上的标簽
下面是他們渲染之後的樣子:
第二部分:自定義伺服器控件編輯器
選擇檔案目錄:
我認為粘貼檔案的目錄路徑是業餘開發人員使用的法子,是以我決定添加一個目錄浏覽器。
開發伺服器控件編輯器所用時間比開發實際控件用的時間更長。
我認為控件的檔案的目錄,應在兩個方面可設定:
Absolute Path: C:\PublicData\ImageFiles\
Virtual Path: ~\xmlFiles\
我試着設計兩個内置浏覽來設定FilesDirectory屬性。
[EditorAttribute(typeof(System.Web.UI.Design.UrlEditor), typeof(UITypeEditor))]
我沒有使用UrlEditor,因為它不允許浏覽外部站點的主目錄。
[EditorAttribute(typeof(System.Windows.Forms.Design.FolderNameEditor), typeof(UITypeEditor))]
我沒有使用FolderNameEditor,因為它沒有提供虛拟路徑的選擇。此外,它迫使使用者選擇一個我不想選擇檔案。
要建立自定義伺服器控件編輯器,就要建立一個類自UITypeEditor繼承和覆寫兩個功能...其中一個啟動一個DialogBox。
下面是代碼:
以下是編輯的DialogBox,如下所示:
我将不會顯示DialogBox代碼,因為這是它比較長,涉及廣。由于缺乏文檔,在開發過程中進行了反複的試錯。但也有一些利益的東西...
目錄分隔符(斜線):
反斜杠像 "\~"這樣被使用的時候,GetProjectItemFromUrl 函數将不能正常使用。它正斜杠:"/~"能正常工作。是以,我確定所有的目錄分隔符使用正斜杠。但是,從目錄浏覽器傳回的目錄使用的是反斜杠。是以我們要確定一緻性...雖然它使代碼有點淩亂,但真的沒有我更喜歡其他選擇。
伺服器控件開發提示:
一旦控件放置到頁面上,你能自動的更新bin檔案路徑下面的DLL,通過右擊右擊控件,選擇“Refresh”。我不得不删除從bin目錄下的控件,然後重新添加到網頁上,以擷取最新版本到該項目中。
調試編輯器:
調試控件是非常容易的。調試控件的編輯器卻非常的難。因為它運作在Visual Studio中。我在不同的地方添加下面代碼:
System.Diagnostics.Debugger.Break();
當運作到斷點,你得到下面這個令人爽快的畫面:
點選 "Debug the program",将建立一個新的 Visual Studio 執行個體。你就能夠調試控件的編輯器了。原來的運作Visual Studio将鎖定的(至少在我這裡是這樣的),你不得不去終止。由于欠缺自定義伺服器控件編輯器的文檔,這是非常寶貴的去尋找和了解什麼被傳遞了,發生了什麼。
可能的改進:
•标題字型可設定(大小,顔色,背景顔色...)
•将名稱放在一個固定的div中,檔案清單在另一可調整大小或有scrollable的div中。
•添加一個布爾字段來選擇顯示在連結的檔案擴充名。
希望這篇文章能夠幫助你。
歡迎讨論,謝謝!
本文轉自麒麟部落格園部落格,原文連結:http://www.cnblogs.com/zhuqil/archive/2009/12/28/HyperlinkFileList.html,如需轉載請自行聯系原作者