成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

ASP.NET MVC控件項(xiàng)目開(kāi)發(fā)的簡(jiǎn)單分析

開(kāi)發(fā) 后端
作者從一個(gè)ASP.NET MVC控件項(xiàng)目開(kāi)始,對(duì)ASP.NET MVC控件進(jìn)行了簡(jiǎn)單的分析,十分深入透徹,希望對(duì)大家有所幫助。

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

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

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

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

控件的顯示截圖

控件顯示截圖

ASP.NET

進(jìn)度條控件

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

Accordion(屬性頁(yè)控件)

上圖中左側(cè)的就是ViewComponentBase類(lèi),其定義了多數(shù)控件屬性,比如js腳本名稱(chēng)和路徑以及相關(guān)樣式以及最終的html元素輸出方法,因?yàn)槠漕?lèi)也是抽象類(lèi),所以其中大部分方法均為定義,而未進(jìn)行具體實(shí)現(xiàn)。我們只要關(guān)注一下其構(gòu)造方法就可以了:

  1. /// <summary> 
  2. /// View component base class.  
  3. /// </summary> 
  4.     public abstract class ViewComponentBase : IStyleableComponent, IScriptableComponent  
  5. {  
  6. private string name;  
  7. private string styleSheetFilesLocation;  
  8. private string scriptFilesLocation;  
  9. /// <summary> 
  10. /// 初始化相關(guān)Initializes a new instance of the <see cref="ViewComponentBase"/> class.  
  11. /// </summary> 
  12. /// <param name="viewContext">當(dāng)前視圖的上下文,將會(huì)在子類(lèi)中使用</param> 
  13. /// <param name="clientSideObjectWriterFactory">傳入當(dāng)前所使用的Writer工廠實(shí)例.通過(guò)子類(lèi)注入,子類(lèi)最終延伸到相對(duì)應(yīng)的控件實(shí)例</param> 
  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<string>();  
  22. ScriptFilesPath = WebAssetDefaultSettings.ScriptFilesPath;  
  23. ScriptFileNames = new List<string>();  
  24. HtmlAttributes = new RouteValueDictionary();  
  25. }  

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

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

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

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

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

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

 

  1. /// <summary> 
  2. /// 創(chuàng)建并寫(xiě)入初始化腳本對(duì)象和相應(yīng)屬性.  
  3. /// </summary> 
  4. /// <param name="writer">The writer.</param> 
  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 類(lèi)型實(shí)例)中被綁定了相關(guān)的控件屬性,并通過(guò)其類(lèi)的WriteInitializationScript(writer)進(jìn)行腳本的輸出。而基本類(lèi)的相應(yīng)方法如下:    

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

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

  1. /// <summary> 
  2. /// 輸出當(dāng)前的 HTML代碼.  
  3. /// </summary> 
  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("<div 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("<div{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("<h3{0}><a href=\"#\">{1}</a></h3>".FormatWith(item.HtmlAttributes.ToAttributeString(), item.Text));  
  28. item.ContentHtmlAttributes.AppendInValue("style", ";", (item == selectedItem) ? "display:block" : "display:none");  
  29. writer.Write("<div{0}>".FormatWith(item.ContentHtmlAttributes.ToAttributeString()));  
  30. item.Content();  
  31. writer.Write("</div>");  
  32. }  
  33. writer.Write("</div>");  
  34. if (!string.IsNullOrEmpty(Theme))  
  35. {  
  36. writer.Write("</div>");  
  37. }  
  38. base.WriteHtml();  
  39. }  

該方法首先獲取當(dāng)前所選屬性頁(yè)標(biāo)簽(GetSelectedItem()方法),然后用foreach方法對(duì)屬性頁(yè)標(biāo)簽集合進(jìn)行遍歷,并判斷當(dāng)前屬性頁(yè)是否就是被選中的屬性頁(yè),并綁定上相應(yīng)的css屬性。其最終也是調(diào)用相應(yīng)的基類(lèi)方法進(jìn)行輸出。當(dāng)然這里基類(lèi)方法也是為空,呵呵。

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

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

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

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

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

屬性頁(yè)發(fā)生變化

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

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

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

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

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

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

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

  1. private TViewComponent Create<TViewComponent>(Func<TViewComponent> 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í)就是之前在該類(lèi)方法Accordion()中所調(diào)用并執(zhí)行的:

  1. return new AccordionBuilder(Create(() => new Accordion(ViewContext, clientSideObjectWriterFactory))); 
通過(guò)該方法,就可以將該控件及其相關(guān)組件信息注冊(cè)到相應(yīng)的視圖中。因?yàn)槲覀儽容^關(guān)注WriteHtml()方法,所以這里就直接分析一下這一行代碼:     
ScriptRegistrar().ToRegistrar().Register(component);
ScriptRegistrar類(lèi)中的Register方法承擔(dān)著將當(dāng)前要?jiǎng)?chuàng)建的組件添加到當(dāng)前的腳本組件列表中的任務(wù)(scriptableComponents為list列表)    
  1.  
  2.        /// <summary> 
  3. /// Registers the scriptable component.  
  4. /// </summary> 
  5. /// <param name="component">The component.</param> 
  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()方法將其顯示出來(lái)(注:該方法與以前web控件開(kāi)發(fā)中的顯示方法同名,所以比較好理解),如下:   

  1.     /// <summary> 
  2. /// Writes the scripts in the response.  
  3. /// </summary> 
  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.     /// <summary> 
  2. /// 寫(xiě)出所有腳本資源和腳本 statements.  
  3. /// </summary> 
  4. /// <param name="writer">The writer.</param> 
  5.       protected virtual void Write(TextWriter writer)  
  6. {  
  7. WriteScriptSources(writer);  
  8. WriteScriptStatements(writer);  
  9. }  

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

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

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

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

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

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

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

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

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

原文標(biāo)題:一個(gè)Asp.net MVC 控件項(xiàng)目分析---Telerik.Web.Mvc

鏈接:http://www.cnblogs.com/daizhj/archive/2009/09/09/1562966.html

【編輯推薦】

  1. 點(diǎn)評(píng)一下ASP.NET的WEB控件
  2. ASP.NET控件學(xué)習(xí)總結(jié)
  3. ASP.NET前臺(tái)控件點(diǎn)評(píng):避免強(qiáng)迫癥,奔向簡(jiǎn)潔高效
  4. ASP.NET 2.0環(huán)境下的Shell函數(shù)
  5. 在ASP.NET 2.0中向數(shù)據(jù)庫(kù)批量插入數(shù)據(jù)
責(zé)任編輯:彭凡 來(lái)源: 博客園
相關(guān)推薦

2009-07-28 14:47:18

ASP.NET MVC

2009-08-04 10:43:59

ASP.NET控件開(kāi)發(fā)

2009-08-07 15:24:16

ASP.NET模板控件

2009-07-31 12:43:59

ASP.NET MVC

2009-03-13 10:58:48

ASP.NetMVC框架編程

2009-07-24 13:20:44

MVC框架ASP.NET

2014-06-30 09:22:38

ASP.NETBootstrap

2009-04-20 09:43:37

ASP.NET MVC基礎(chǔ)開(kāi)發(fā)

2009-07-29 09:04:36

JQRTEasp.net mvc

2009-07-27 13:52:36

Panel控件ASP.NET

2009-08-04 12:59:42

ASP.NET控件開(kāi)發(fā)

2009-08-07 14:42:02

ASP.NET控件開(kāi)發(fā)

2009-07-24 15:46:00

ASP.NET登陸控件

2009-08-07 15:34:15

ASP.NET數(shù)據(jù)綁定

2011-07-12 15:17:02

ASP.net服務(wù)器控件

2009-08-06 18:18:27

ASP.NET控件開(kāi)發(fā)ASP.NET復(fù)合控件

2009-07-20 15:44:32

ASP.NET MVC

2009-07-22 09:11:02

Action方法ASP.NET MVC

2009-07-29 02:40:00

asp.net mvc

2009-07-22 13:24:24

ASP.NET MVC
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 欧美亚洲综合久久 | 亚洲一区中文字幕在线观看 | 国产精品成人一区二区三区 | 国产大学生情侣呻吟视频 | 日韩免费中文字幕 | 日本成人在线观看网站 | 在线视频一区二区 | 91精品久久久 | 亚洲激情在线视频 | 欧美一级片在线看 | 亚洲国产成人精品久久久国产成人一区 | 丝袜美腿av | 四虎最新视频 | 99久久99久久精品国产片果冰 | av网站免费| 久久伊人影院 | 一级黄色片免费在线观看 | 激情欧美日韩一区二区 | 日韩美av| 久草热视频 | 国产中文区二幕区2012 | 日韩免费网站 | 91综合在线观看 | 亚洲一区二区久久 | 国内精品久久久久久 | 久久久一区二区三区四区 | 黄色免费网站在线看 | 欧美一区二区三区在线播放 | 久久99精品久久久久久国产越南 | 欧美日批 | 精品美女视频在线观看免费软件 | 亚洲一区二区免费电影 | 97视频精品 | 在线a视频 | 日韩精品一区二区久久 | 天天操天天天干 | 欧美二区在线 | 91久久精品国产91久久性色tv | 一级黄色生活视频 | 久久婷婷国产香蕉 | 中文字幕亚洲一区二区三区 |