IT餐館—第二十二回 控件

    週三中午吃完飯,雨辰從食堂回來,發現開發小組中的一位姓黃的同事(組裏管他叫老黃牛)正在看一本.net的書,因爲這幾年雨辰已基本上不再買技術類的書了,因爲真正看的上眼有價值、有水準的書籍前些年基本都翻遍了。雨辰帶着好奇心走過去問老黃關於該書的一些情況,因爲已過了對那些所謂標以‘入門’、‘精通’,‘深入淺出’,‘寶典’之類圖書的‘感冒期’,所以就單刀直入,問了老黃正在看的部分。
    老黃也很高興有人一起交流,就說:“目前正在看關於控件開發方面的內容,該書用了近50頁的篇幅來介紹控件的原理,開發流程,相關函數方法,示例啥的。” 
    雨辰笑着對他說:“具我所知,在.net中控件分爲自定義控件和用戶控件,其中用戶控件我接觸的比較早,這些年也一直在用,特別是web用戶控件。而web自定義控件是加入到產品組之後纔開始設計使用的。不過這些年走過來倒是有些心得,不知道黃兄有興趣聽不。” 
    老黃點點頭:“當然了,我之前在上家公司也開發設計過一些用戶控件,感覺還是挺容易上手的。” 
    雨辰拍拍老黃的肩膀,笑着說:“的確如此,其實我感覺控件的好處有幾方面,首先就是提升代碼的可複用性,進而封裝可複用的業務邏輯(這主要體現在用戶控件上)。其次是緩存,其提供了一種可以緩存頁面局部信息的方法,比如在web用戶控件頭添加聲明:
      <%OutputCache Duration= "300 " VaryByParam= "none "%>
 
    而第三點是用戶控件也提供了一個不錯的AJAX調用方式,之前就曾有人在網上使用ajaxHelper的方式來實現加載ascx文件並獲取相應的返回信息之後,加載並刷新當面頁面指定區域(通常是div元素)。” 
    “你前兩點我認同,但第三點是什麼意思呀,我怎麼聽不太明白?”老黃不解的問。 
    雨辰解釋說:“其實原理很簡單,就是你在一個叫ajax.aspx的頁面上放一個form標籤,其runat"server",然後在ajax.aspx.cs文件的Page_Load事件中使用該formcontrols屬性,並調用該屬性的add方法來加載指定的用戶控件(作爲參數傳入),這時該ajax.aspx頁面就會顯示指定的用戶控件的輸出內容了。當然在ajax.aspx頁面中會有一個標籤用於記錄當前的頁面中用戶控件顯示信息的‘區域’,這樣在使用prototype.js這類框架中的ajax功能時,就可以直接向ajax.aspx頁面傳遞要調用的用戶控件‘參數’,並將控件加載後返回的頁面信息截取出來,做爲ajax調用的返回結果,用於刷新指定頁面元素(通常是div)中的innerHtml屬性。說了這些,我給你個鏈接,你可以看看其最終的實現代碼(代碼鏈接 
    聽了雨辰這麼說,老黃才明白了到底怎麼回事,說:“不過我感覺這個ajax.aspx就像個代理一樣,呵呵,不過這也算是提供了一個不錯的思路了。因爲我以前都是用ajax請求一個可執行的頁面或鏈接,比如 aspxashxasmx。” 
    雨辰笑着說:“這也說明了web用戶控件的開發與web頁面還是很接近的,呵呵。另外就是在剛學習和開發用戶控件時往往還會犯一些小毛病。” 
    老黃聽雨辰這麼說,問道:“哪些毛病?!” 
    “首先就是將一些特殊的業務邏輯加入到用戶控件代碼中,降低了控件的通用性。其次就是有些人習慣於在web用戶控件上只放一個LABLE,然後就用CS文件來填充其.text屬性。這不是什麼好習慣。對於複雜的數據展示就應該使用Repeater,Datagrid等控件,甚至要複合幾個控件來滿足需求,而這種將數據和顯示控件代碼硬編碼到一起的做法,會讓後續的代碼分離,閱讀理解都會帶來不少的麻煩。另外我發現有些開發者習慣於把web用戶控件的所有CS代碼都放到Page_load事件中,但因爲用戶控件的CS文件中也有OnInit 、InitializeComponent等方法(與page相似),應根據當前要實現的功能將代碼均勻分佈相應的事件代碼中,比如初始化組件代碼、數據綁定到控件的代碼,頁面顯示代碼等。這三個毛病只是其中的一部分,應該有一定的代表性了。” 雨辰邊想邊說。 
    老黃點了點頭。不過我還有個問題,之前我曾在項目中爲所有的web用戶控件構造了一個基類,在這個基類中提供了一些公有屬性,比如控件版本號,控件名稱以及一些常用屬性的初始化操作等等,這樣在其派生子類(控件)中可以直接使用這些被初始化好的屬性了。當然我還想一些跳轉邏輯寫到這個控件基類中,比如在管理後臺操作中,如用戶身份驗證出現問題時,就可以完成跳轉,而不能等執行到主頁面page_load時再跳轉,不知道這個做有什麼問題沒有。” 
    雨辰笑着說:“你抽取出一個控件基類的作法我沒什麼異議,只是在‘是否在用戶控件中提供跳轉操作’的想法有些差別。當然你這樣寫也能完成你想要實現的功能。但我認爲對用戶身份權限校驗這類的操作還是應該放到控件所屬的主頁面或業務邏輯層爲宜,因爲控件完成的只是做數據綁定,顯示數據這類工作,如果摻雜過多的特殊業務邏輯會降低控件的通用性。另外如果讓控件基類做這種權限類的操作時,你必須還要提供相應的‘開關’屬性,因爲不是所有的應用場景都需要對用戶權限進行校驗,這無形中也增加了使用控件的‘難度係數’,甚至讓人產生歧義。當然如果你的這類控件只想用於我之前所說的那種ajax調用的話,那還說得過去,因爲它很類似於直接調用aspx頁面,這樣當客戶端請求用戶控件時,通過對其所提供的身份信息進行驗證,返回相應的結果或校驗錯誤信息,這倒是一個不錯的思路。” 
    老黃笑着說:“你說要將頁面跳轉這類的代碼放到什麼地方呢?” 
    雨辰想了想,在旁邊的黑板上寫了一些東西,內容如下: 
    主頁面屬性 -->主頁面的構造函數--> 用戶控件屬性-->用戶控件的構造函數-->用戶控件的OnInit事件-->用戶控件的InitializeComponent方法-->主頁面的OnInit事件-->主頁面的InitializeComponent方法-->主頁面的Page_Load()-->用戶控件頁的Page_Load()

 
    然後轉過身對老黃說:“這是對有用戶控件的頁面的執行流程,如果我要寫權限驗證的邏輯,我會將其放到第二步,也就是主頁面的構造函數中,這樣就可以在‘驗證操作’不通過的情況下,不再依次執行後續的控件初始以及page_load方法了,相信在速度上也會快許多,不過如果在構造方法中使用Response.Redirect(…)這類的寫法可能會出問題,我建議使用System.Web.HttpContext.Current.Response.Redirect(),這樣就差不多了。 
    老黃看着這個執行流程,想了想自己開發的代碼,說:“一會我回去測一下這個流程,如果如你所說的話,那我要改的地方就多了,呵呵。” 
    雨辰接着說:“其實開發控件是需要對頁面和控件生命週期有一定了解的。特別是開發自定義控件。因爲用戶控件提供了.ascx和相應的.ascx.cs文件,這樣就很便於將數據綁定與顯示邏輯進行代碼分離,同時其開發起來與進行webform頁面開發有很多相似之處,甚至在剛上手時沒什麼區別,所以難度不是很大。而自定義控件就有所不同了,其自身沒有前臺界面文件(比如ascx等),所有的代碼都是在相應.cs文件中提供的,比如要開發在web頁面中使用的自定義控件,就需要繼承WebControlControl,並實現Render(HtmlTextWriter pOutPut) 方法。” 
    雨辰把水杯拿過來喝了一口水然後繼續說道:“另外我更傾向於在用戶控件中加入更多的業務邏輯,而在自定義控件中的業務邏輯就沒那麼重要了,因爲自定義控件應該更強調其通用性、易用性的一面,比如之前在用戶控件中拖入lable這類自定義控件等。另外在自定義控件開發中要考慮webpage和控件生命週期、事件機制回傳事件視圖狀態等問題及與之相關的流程函數。所以我感覺自定義控件開發要將更多的精力放在控件的通用性(比如可以在winformwebform中同時使用),還有控件底層實現機制上的理解上。有人說開發自定義控件要比用戶控件複雜,原因就在於此。” 
    老黃說:“的確,我也認爲做web型的自定義控件也要了解頁面生命週期相關的內容,目前我還在開發設計用戶控件階段,沒有涉足到自定義控件方面,呵呵。” 
    雨辰笑着說:“這只是時間問題,呵呵。另外就是我這些年開發控件時大體經歷了四個階段:
    1.上手階段,這一階段把什麼代碼都放在一個cs或一個類中,並不根據其控件行爲,結構的複雜性進行類層面上的定義分解,比如要開發tab控件時,就應該將相應的屬性頁分解成一個cs類文件,這樣就可以把整個tab控件看成是一個個屬性頁的‘集合’來進行‘複合處理’(使用CreateChildControls創建子控件)。
    2.看開源或破解的第三方商業控件庫代碼(有些不道德,但是個學習途徑),這時才發現自己寫的就是垃圾,看出了與別人的差距。感覺自己的水平就像是小學生,自信心受到了空前的打擊,甚至不敢再進行開發。
    3.收拾起‘殘破’的自信心,研究相應的優秀代碼,同時深研底層實現(比如用reflector.net中的控件‘源碼’,同時再看一些.net出現之前的那些控件及其實現代碼(比如MFC,DELPHI控件庫),從對底層的理解上更上一層樓。
    4.爲控件提供界面豐富的‘設計時支持’,比如使用PropertyGrid(屬性表)以及繼承並實現ControlDesigner(位於System.Web.UI.Design名空間)並重寫GetDesignTimeHtml()方法,這樣就可以允許用戶在VS中的設計器中對控件‘手動’進行初始化,這一點可以想想我們以前使用TreeView這類控件時,手工添加樹形結點的情況。 
    當然要開發好web控件,對cssjs還要有一定理解,必定有時用樣式或JS實現要比用cs代碼要更方便,靈活,可定製性更好。只不過這方面商業控件要考慮js腳本加密、混淆等問題了。” 
    老黃點了點頭說:“其實介紹如何開發控件就可以寫上幾本書了,看老外那邊光一個列表控件就可以賣幾百美刀,感覺真有大有‘錢途’呀。” 
    雨辰苦笑着說:“誰說不是呢,哎! 另外目前國外的控件開發商都有功能豐富、界面華麗的產品,比如 ComponentArt, telerik , devexpress, componentone, infragistics, netikatech等等,並且其研發步伐往往還緊隨像微軟這樣的IT巨頭,比如silverlight這類技術的相關控件研發,我看其活得都挺‘滋潤’。但國內控件開發者的生存狀況就不太樂觀了,必定這一產品是要以技術爲支撐的,其使用的‘客戶’往往也是開發者,比行業軟件開發者還要‘幕後’。另外大家對軟件‘免費’有過多的依賴和‘誤解’。所以國內通過開發控件走商業化,要比軟件商業化更難,甚至是‘無解’。比如大家對一款商業化好用的控件庫往往抱着下面的看法:
    1.首先是想到破解版(最好還能有源碼)。
    2.考慮其它可以免費使用該控件的途徑。
    3.如沒有其它路子,就想自己能否開發一款相類似的控件出來 (往往開發週期長或功能過於複雜而作罷)
    4.如果此路不通,再看看有無開源的項目來做替代品。有時最後因爲不願付費,而最終改變了軟件的界面設計,給用戶使用上造成困擾,用戶體驗也不好,甚至很BT。”
    老黃笑着說:“目前你說的這些我基本贊同,但我還是希望國內商業控件公司能有不錯的發展,必定這是一個方向呀,之前曾在csdn上看過一家國內公司提出基於業務組件(實際也就是控件)開發,換句話說只要把幾個組件(或控件)拖拽到窗體或頁面中,簡單設置一個屬性,開發就完成了,多方便呀!” 
    雨辰壞笑着說:“如果真要有那一天,那你我就都TM失業了,因爲到那時老闆或業務專家,就可以完成軟件開發,還要你我幹什麼,呵呵。” 
    這時雨辰看了一下時間差不多了,寒暄幾句之後,就回座位工作了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章