日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
ASP.NETMVC控件項(xiàng)目開發(fā)的簡單分析

【編者按】對于ASP.NET MVC框架大家一定不會(huì)陌生,但是對于很多人來說,弄好一個(gè)ASP.NET MVC控件項(xiàng)目實(shí)在是費(fèi)勁的事情。這里由作者來介紹他的一個(gè)ASP.NET MVC控件項(xiàng)目經(jīng)歷。編輯推薦《ASP.NET MVC框架視頻教程》

創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供岱山網(wǎng)站建設(shè)、岱山做網(wǎng)站、岱山網(wǎng)站設(shè)計(jì)、岱山網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、岱山企業(yè)網(wǎng)站模板建站服務(wù),十年岱山做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。

在寫本文之前,本人一直抱著‘不宜’在ASP.NET MVC框架下搞什么控件開發(fā)的想法,因?yàn)橐惶岬娇丶蜁?huì)讓人想起‘事件’,‘VIEWSTATE’等一些問題,而ASP.NET MVC下是Controller, Action, Viewpage, Filter等特性的‘天下’。所以總感覺‘驢唇對不上馬嘴’。

但直到前陣子在郵箱中收到了關(guān)于telerik關(guān)于MVC框架擴(kuò)展的一些信息之后,才發(fā)現(xiàn)這家商業(yè)控件公司也開始打MVC的主意了。而這個(gè)項(xiàng)目(開源)就是該公司在理解了asp.net mvc的基礎(chǔ)上所做的一些嘗試,當(dāng)然其所實(shí)現(xiàn)的所謂控件與之前我們在項(xiàng)目中所開發(fā)或使用的web服務(wù)器控件有很大的不同,可以說是拋棄了以往的設(shè)計(jì)方式。盡管目前它的這種做法我心里還打著問號,但必定是一種嘗試(不管你贊同還是不贊同)。下面就做一個(gè)簡單的分析,希望能給研究MVC架構(gòu)的朋友提供一些的思考。

首先要聲明的是該開源項(xiàng)目中所使用的js就是jquery,而那些顯示效果也基本上就是基于jQuery中的那件插件為原型,并進(jìn)行相應(yīng)的屬性封裝,以便于在viewpage中用C#等語言進(jìn)行聲明綁定。下面就其中一些控件的顯示截圖:

在該開源項(xiàng)目中,所有控件均基于jQueryViewComponentBase (abstract 類型),但其自身屬性并不多,而所有的控件基類屬性都被jQueryViewComponentBase 的父類ViewComponentBase所定義,下面以控件中的“Accordion(屬性頁控件)”為例進(jìn)行說明,見下圖:

上圖中左側(cè)的就是ViewComponentBase類,其定義了多數(shù)控件屬性,比如js腳本名稱和路徑以及相關(guān)樣式以及最終的html元素輸出方法,因?yàn)槠漕愐彩浅橄箢悾云渲写蟛糠址椒ň鶠槎x,而未進(jìn)行具體實(shí)現(xiàn)。我們只要關(guān)注一下其構(gòu)造方法就可以了:

 
 
 
 
  1. ///  
  2. /// View component base class.  
  3. ///  
  4.     public abstract class ViewComponentBase : IStyleableComponent, IScriptableComponent  
  5. {  
  6. private string name;  
  7. private string styleSheetFilesLocation;  
  8. private string scriptFilesLocation;  
  9. ///  
  10. /// 初始化相關(guān)Initializes a new instance of the  cref="ViewComponentBase"/> class.  
  11. ///  
  12. ///  name="viewContext">當(dāng)前視圖的上下文,將會(huì)在子類中使用 
  13. ///  name="clientSideObjectWriterFactory">傳入當(dāng)前所使用的Writer工廠實(shí)例.通過子類注入,子類最終延伸到相對應(yīng)的控件實(shí)例 
  14.         protected ViewComponentBase(ViewContext viewContext, IClientSideObjectWriterFactory clientSideObjectWriterFactory)  
  15. {  
  16. Guard.IsNotNull(viewContext, "viewContext");  
  17. Guard.IsNotNull(clientSideObjectWriterFactory, "clientSideObjectWriterFactory");  
  18. ViewContext = viewContext;  
  19. ClientSideObjectWriterFactory = clientSideObjectWriterFactory;  
  20. StyleSheetFilesPath = WebAssetDefaultSettings.StyleSheetFilesPath;  
  21. StyleSheetFileNames = new List();  
  22. ScriptFilesPath = WebAssetDefaultSettings.ScriptFilesPath;  
  23. ScriptFileNames = new List();  
  24. HtmlAttributes = new RouteValueDictionary();  
  25. }  

通過上述的構(gòu)造方法,就可以將控件的一些通用默認(rèn)屬性值進(jìn)行初始化了。

下面以“Accordion”的源碼來分析一下,這里還是從構(gòu)造方法入手:

   
  
  
  
  1. public class Accordion : jQueryViewComponentBase, IAccordionItemContainer  
  2. {  
  3. ……  
  4. ///  
  5. /// Initializes a new instance of the  cref="Accordion"/> class.  
  6. ///  
  7. ///  name="viewContext">The view context. 
  8. ///  name="clientSideObjectWriterFactory">The client side object writer factory. 
  9.        public Accordion(ViewContext viewContext, IClientSideObjectWriterFactory clientSideObjectWriterFactory) : base(viewContext, clientSideObjectWriterFactory)  
  10. {  
  11. Items = new List();  
  12. autoHeight = true;  
  13. }  

注:上面的構(gòu)程方法后面加入了base(viewContext, clientSideObjectWriterFactory),以實(shí)現(xiàn)向基類構(gòu)造方法傳參,也就是實(shí)現(xiàn)了上面所說的將當(dāng)前控件所使用的viewContext,clientSideObjectWriterFactory傳遞到基類ViewComponentBase 中去。(注:最終的clientSideObjectWriterFactory為ClientSideObjectWriterFactory實(shí)例類型)。

當(dāng)然,因?yàn)樵摽丶闹邢鄳?yīng)屬性比較簡單,只是一些set,get語法,所以就不過多介紹了,相信做過控件開發(fā)的對這些再熟悉不過了。

下面主要介紹一下其write html元素時(shí)所使用的方法,如下:

  
  
  
  
  1. ///  
  2. /// 創(chuàng)建并寫入初始化腳本對象和相應(yīng)屬性.  
  3. ///  
  4. ///  name="writer">The writer. 
  5.       public override void WriteInitializationScript(TextWriter writer)  
  6. {  
  7. int selectedIndex = Items.IndexOf(GetSelectedItem());  
  8. IClientSideObjectWriter objectWriter = ClientSideObjectWriterFactory.Create(Id, "accordion", writer);  
  9. objectWriter.Start()  
  10. .Append("active", selectedIndex, 0)  
  11. .Append("animated", AnimationName)  
  12. .Append("autoHeight", AutoHeight, true)  
  13. .Append("clearStyle", ClearStyle, false)  
  14. .Append("collapsible", CollapsibleContent, false)  
  15. .Append("event", OpenOn)  
  16. .Append("fillSpace", FillSpace, false);  
  17. if (!string.IsNullOrEmpty(Icon) || !string.IsNullOrEmpty(SelectedIcon))  
  18. {  
  19. if (!string.IsNullOrEmpty(Icon) && !string.IsNullOrEmpty(SelectedIcon))  
  20. {  
  21. objectWriter.Append("icons:{'header':'" + Icon + "','headerSelected':'" + SelectedIcon + "'}");  
  22. }  
  23. else if (!string.IsNullOrEmpty(Icon))  
  24. {  
  25. objectWriter.Append("icons:{'header':'" + Icon + "'}");  
  26. }  
  27. else if (!string.IsNullOrEmpty(SelectedIcon))  
  28. {  
  29. objectWriter.Append("icons:{'headerSelected':'" + SelectedIcon + "'}");  
  30. }  
  31. }  
  32. objectWriter.Append("change", OnChange).Complete();  
  33. base.WriteInitializationScript(writer);  
  34. }  

可以看出,objectWriter (IClientSideObjectWriter 類型實(shí)例)中被綁定了相關(guān)的控件屬性,并通過其類的WriteInitializationScript(writer)進(jìn)行腳本的輸出。而基本類的相應(yīng)方法如下:    

  
  
  
  
  1.  ///  
  2. /// Writes the initialization script.  
  3. ///  
  4. ///  name="writer">The writer. 
  5.       public virtual void WriteInitializationScript(TextWriter writer)  
  6. {  
  7. }  

大家看到該方法為空,但其又是如何運(yùn)行起來的呢,這里先賣個(gè)關(guān)子,稍后再說。接著再看一下另一個(gè)方法:WriteHtml()

   
   
   
   
  1. ///  
  2. /// 輸出當(dāng)前的 HTML代碼.  
  3. ///  
  4.       protected override void WriteHtml()  
  5. {  
  6. AccordionItem selectedItem = GetSelectedItem();  
  7. TextWriter writer = ViewContext.HttpContext.Response.Output;  
  8. if (!string.IsNullOrEmpty(Theme))  
  9. {  
  10. writer.Write(" class=\"{0}\">".FormatWith(Theme));  
  11. }  
  12. HtmlAttributes.Merge("id", Id, false);  
  13. HtmlAttributes.AppendInValue("class", " ", "ui-accordion ui-widget ui-helper-reset");  
  14. writer.Write("{0}>".FormatWith(HtmlAttributes.ToAttributeString()));  
  15. foreach (AccordionItem item in Items)  
  16. {  
  17. item.HtmlAttributes.AppendInValue("class", " ", "ui-accordion-header ui-helper-reset ui-state-default ");  
  18. item.ContentHtmlAttributes.AppendInValue("class", " ", "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");  
  19. if (item == selectedItem)  
  20. {  
  21. item.ContentHtmlAttributes.AppendInValue("class", " ", "ui-accordion-content-active");  
  22. }  
  23. else  
  24. {  
  25. item.HtmlAttributes.AppendInValue("class", " ", "ui-corner-all");  
  26. }  
  27. writer.Write("{0}> href=\"#\">{1}".FormatWith(item.HtmlAttributes.ToAttributeString(), item.Text));  
  28. item.ContentHtmlAttributes.AppendInValue("style", ";", (item == selectedItem) ? "display:block" : "display:none");  
  29. writer.Write("{0}>".FormatWith(item.ContentHtmlAttributes.ToAttributeString()));  
  30. item.Content();  
  31. writer.Write("
");  
  • }  
  • writer.Write("
  • ");  
  • if (!string.IsNullOrEmpty(Theme))  
  • {  
  • writer.Write("
  • ");  
  • }  
  • base.WriteHtml();  
  • }  
  • 該方法首先獲取當(dāng)前所選屬性頁標(biāo)簽(GetSelectedItem()方法),然后用foreach方法對屬性頁標(biāo)簽集合進(jìn)行遍歷,并判斷當(dāng)前屬性頁是否就是被選中的屬性頁,并綁定上相應(yīng)的css屬性。其最終也是調(diào)用相應(yīng)的基類方法進(jìn)行輸出。當(dāng)然這里基類方法也是為空,呵呵。

    準(zhǔn)備好了這個(gè)控件類之后,Telerik還為Accordion控件‘準(zhǔn)備’了一些輔助組件,比如屬性頁組件(AccordionItem),以及相關(guān)的組件構(gòu)造器(AccordionItemBuilder,AccordionBuilder),這樣我們就可以通過這些構(gòu)造器很方便的創(chuàng)建相應(yīng)的控件和組件了,下面就以AccordionItemBuilder為例,解釋一下其構(gòu)造器結(jié)構(gòu):

         
         
         
         
    1. public class AccordionBuilder : ViewComponentBuilderBase, AccordionBuilder>, IHideObjectMembers  
    2. {  
    3. ///  
    4. /// 初始化方法Initializes a new instance of the  cref="AccordionBuilder"/> class.  
    5. ///  
    6. ///  name="component">The component. 
    7.       public AccordionBuilder(Accordion component) : base(component)  
    8. {}  
    9. ///  
    10. /// 指定一個(gè)屬性頁選項(xiàng)  
    11. ///  
    12. ///  name="addAction">要添加的action. 
    13. ///  
    14.       public virtual AccordionBuilder Items(Action addAction)  
    15. {  
    16. Guard.IsNotNull(addAction, "addAction");  
    17. AccordionItemFactory factory = new AccordionItemFactory(Component);  
    18. addAction(factory);  
    19. return this;  
    20. }  
    21. ///  
    22. /// 屬性頁動(dòng)態(tài)效果顯示名稱(鼠標(biāo)在屬性頁移入移出時(shí))  
    23. ///  
    24. ///  name="effectName">Name of the effect. 
    25. ///  
    26.       public virtual AccordionBuilder Animate(string effectName)  
    27. {  
    28. Component.AnimationName = effectName;  
    29. return this;  
    30. }  
    31. ///  
    32. /// 是否高度自適用.  
    33. ///  
    34. ///  name="value">if set to true value. 
    35. ///  
    36.       public virtual AccordionBuilder AutoHeight(bool value)  
    37. {  
    38. Component.AutoHeight = value;  
    39. return this;  
    40. }  
    41.  
    42. ///  
    43. /// 指定要觸發(fā)的屬性頁事件名稱.  
    44. ///  
    45. ///  name="eventName">Name of the event. 
    46. ///  
    47.       public virtual AccordionBuilder OpenOn(string eventName)  
    48. {  
    49. Component.OpenOn = eventName;  
    50. return this;  
    51. }  
    52. ///  
    53. /// 所使用的Icons名稱.  
    54. ///  
    55. ///  name="name">The name. 
    56. ///  
    57.       public virtual AccordionBuilder Icon(string name)  
    58. {  
    59. Component.Icon = name;  
    60. return this;  
    61. }  
    62. ///  
    63. /// 被選中的屬性頁所使用的Icons 名稱  
    64. ///  
    65. ///  name="name">The name. 
    66. ///  
    67.       public virtual AccordionBuilder SelectedIcon(string name)  
    68. {  
    69. Component.SelectedIcon = name;  
    70. return this;  
    71. }  
    72. ///  
    73. /// 當(dāng)屬性頁發(fā)生變化時(shí)要傳遞的action 腳本.  
    74. ///  
    75. ///  name="javaScript">The java script. 
    76. ///  
    77.       public virtual AccordionBuilder OnChange(Action javaScript)  
    78. {  
    79. Component.OnChange = javaScript;  
    80. return this;  
    81. }  
    82. ///  
    83. /// Specify the name of the theme applies to the accordion.  
    84. ///  
    85. ///  name="name">The name. 
    86. ///  
    87.       public virtual AccordionBuilder Theme(string name)  
    88. {  
    89. Component.Theme = name;  
    90. return this;  
    91. }  
    92. }  

    對于上面的OnChange方法,可以使用下面的方法將相應(yīng)的js腳本傳入并執(zhí)行

          
         
         
         
    1. .OnChange(() => 
    2. {%> 
    3. function(event, ui)  
    4. {  
    5. $('#trace').append('Change fired: ' + new Date() + '
      ');  
    6. }  
    7. <%}  
    8. )  

    這樣,當(dāng)屬性頁發(fā)生變化時(shí),就會(huì)在頁面的指定區(qū)域?qū)⒆兓瘯r(shí)間顯示出來了,如下圖:

    Telerik在jQueryViewComponentFactory中對項(xiàng)目中每一個(gè)控件提供了一個(gè)方法用以初始化相應(yīng)的構(gòu)造器,以便于創(chuàng)建相應(yīng)的控件,比如Accordion,形如: 

           
          
          
          
    1.  ///  
    2. /// Creates a accordion for ASP.NET MVC view.  
    3. ///  
    4. ///  
    5.      [DebuggerStepThrough]  
    6. public virtual AccordionBuilder Accordion()  
    7. {  
    8. return new AccordionBuilder(Create(() => new Accordion(ViewContext, clientSideObjectWriterFactory)));  
    9. }  

    而對于其在VIEW中的使用,則通過擴(kuò)展方法來加以聲明:

          
         
         
         
    1. public static class HtmlHelperExtension  
    2. {  
    3. private static readonly IClientSideObjectWriterFactory factory = new ClientSideObjectWriterFactory();  
    4. ///  
    5. /// Gets the jQuery view components instance.  
    6. ///  
    7. ///  name="helper">The html helper. 
    8. /// jQueryViewComponentFactory 
    9.        [DebuggerStepThrough]  
    10. public static jQueryViewComponentFactory jQuery(this HtmlHelper helper)  
    11. {  
    12. return new jQueryViewComponentFactory(helper, factory);  
    13. }  
    14. }  

    這樣在頁面視圖中,我們這可以使用下面的寫法來構(gòu)造一個(gè)Accordion控件了:

           
          
          
          
    1. <% Html.jQuery().Accordion()  
    2. .Name("myAccordion")  
    3. .Animate("bounceslide")  
    4. .Items(parent => 
    5. ……  

    上面只是介紹了前臺和底層代碼如果顯示的問題,但還沒有解釋之前所說的WriteInitializationScript(TextWriter writer)方法以及WriteHtml()
    方法如何被調(diào)用的問題,正如之前所看到的,因?yàn)锳ccordion的基類ViewComponentBase中未實(shí)現(xiàn)具體的代碼,所以這里我們要將注意力轉(zhuǎn)移到 jQueryViewComponentFactory中,請看如下代碼: 

          
          
          
          
    1. private TViewComponent Create(Func factory) where TViewComponent : ViewComponentBase  
    2. {  
    3. TViewComponent component = factory();  
    4. if (component is jQueryViewComponentBase)  
    5. {  
    6. component.AssetKey = DefaultAssetKey;  
    7. }  
    8. htmlHelper.Telerik().StyleSheetRegistrar().ToRegistrar().Register(component);  
    9. htmlHelper.Telerik().ScriptRegistrar().ToRegistrar().Register(component);  
    10. return component;  
    11. }  

    上面的方法其實(shí)就是之前在該類方法Accordion()中所調(diào)用并執(zhí)行的:

             
            
            
            
    1. return new AccordionBuilder(Create(() => new Accordion(ViewContext, clientSideObjectWriterFactory))); 

    通過該方法,就可以將該控件及其相關(guān)組件信息注冊到相應(yīng)的視圖中。因?yàn)槲覀儽容^關(guān)注WriteHtml()方法,所以這里就直接分析一下這一行代碼:      ScriptRegistrar().ToRegistrar().Register(component); ScriptRegistrar類中的Register方法承擔(dān)著將當(dāng)前要?jiǎng)?chuàng)建的組件添加到當(dāng)前的腳本組件列表中的任務(wù)(scriptableComponents為list列表)    

              
             
             
             
    1.  
    2.        ///  
    3. /// Registers the scriptable component.  
    4. ///  
    5. ///  name="component">The component. 
    6.        public virtual void Register(IScriptableComponent component)  
    7. {  
    8. Guard.IsNotNull(component, "component");  
    9. if (!scriptableComponents.Contains(component))  
    10. {  
    11. scriptableComponents.Add(component);  
    12. }  
    13. }  

    當(dāng)組件被成功添加到該list列表中后,系統(tǒng)就會(huì)調(diào)用Render()方法將其顯示出來(注:該方法與以前web控件開發(fā)中的顯示方法同名,所以比較好理解),如下:   

              
             
             
             
    1.     ///  
    2. /// Writes the scripts in the response.  
    3. ///  
    4.       public void Render()  
    5. {  
    6. if (hasRendered)  
    7. {  
    8. throw new InvalidOperationException(Resources.TextResource.YouCannotCallRenderMoreThanOnce);  
    9. }  
    10. if (ViewContext.HttpContext.Request.Browser.EcmaScriptVersion.Major >= 1)  
    11. {  
    12. Write(ViewContext.HttpContext.Response.Output);  
    13. }  
    14. hasRendered = true;  
    15. }  

    注意上面的這一行代碼:

    Write(ViewContext.HttpContext.Response.Output);

    其所實(shí)現(xiàn)的功能如下:  

            
            
            
            
    1.     ///  
    2. /// 寫出所有腳本資源和腳本 statements.  
    3. ///  
    4. ///  name="writer">The writer. 
    5.       protected virtual void Write(TextWriter writer)  
    6. {  
    7. WriteScriptSources(writer);  
    8. WriteScriptStatements(writer);  
    9. }  

    而就是WriteScriptStatements這行代碼開始執(zhí)行之前所說的那個(gè)WriteInitializationScript(TextWriter writer)。而WriteHtml()方法的執(zhí)行入口要更加復(fù)雜一些,因?yàn)門elerik提供了ViewComponentBuilderBase這個(gè)類來進(jìn)行視圖組件的構(gòu)造,而該類中的Render方法就是對相應(yīng)組件的Render方法(組件中已定義)進(jìn)行調(diào)用,如下:

            
            
            
            
    1.     ///  
    2. /// Renders the component.  
    3. ///  
    4.     public virtual void Render()  
    5. {  
    6. Component.Render();  
    7. }  

    而之前的“Accordion”控件是繼承自ViewComponentBase類,所以相應(yīng)組件的Render方法就在該類中進(jìn)行了聲明定義,如下:

              
             
             
             
    1.   ///  
    2. /// Renders the component.  
    3. ///  
    4.      public void Render()  
    5. {  
    6. EnsureRequired();  
    7. WriteHtml();  
    8. }  

    大家看到了第二行代碼了吧,這就是我們之前看到的那個(gè)方法,也就是Accordion組件中WriteHtml()重寫方法的調(diào)用入口。

    繞了這么一大圈,才把這個(gè)流程理清,是不是有些暈了。的確,剛開始接觸時(shí)我也有點(diǎn)暈,但暈呀暈呀就‘暈過去了’,現(xiàn)在再回頭看起來感常見其整體的架構(gòu)思路還是很清晰的。可以說有了這瓶酒墊底,再分析該項(xiàng)目中的其它控件就‘如魚得水’了。

    ***不妨總結(jié)一下:

    這是對ASP.NET MVC控件項(xiàng)目開發(fā)做的一次嘗試,但如果之前做過控件特別是web服務(wù)器端控件開發(fā)的朋友,可以看出項(xiàng)目中有非常重的web控件開發(fā)味道,基本連方法名稱都有一定的重疊。

    另外就是其自身還是引用了組件對象模型的概念,就拿屬性頁控件來說,就將其分為Accordion和AccordionItem兩種類型,其中可以將Accordion看成是AccordionItem的集合封裝(包括遍歷操作),而這里AccordionItem就成了Accordion的一個(gè)組件,而Accordion又是當(dāng)前view中的一個(gè)組件。而組件開發(fā)一直是.NET平臺上所倡導(dǎo)的。其優(yōu)勢在于可復(fù)用,維護(hù)方便,簡化復(fù)雜問題等。


    網(wǎng)站欄目:ASP.NETMVC控件項(xiàng)目開發(fā)的簡單分析
    瀏覽路徑:http://m.5511xx.com/article/cdcighd.html