<style> body {padding:0;margin:0;}</style>
在写本文之前,本人一直抱着‘不宜’在asp.net MVC框架下搞什么控件开发的想法,因为一提到控件就会让人想起‘事件’,‘VIEWSTATE’等一些问题,而asp.net MVC下是Controller, Action, Viewpage, Filter等特性的‘天下’。所以总感觉‘驴唇对不上马嘴’。
但直到前阵子在邮箱中收到了关于telerik关于MVC框架扩展的一些信息之后,才发现这家商业控件公司也开始打MVC的主意了。而这个项目(开源)就是该公司在理解了asp.net mvc的基础上所做的一些尝试,当然其所实现的所谓控件与之前我们在项目中所开发或使用的web服务器控件有很大的不同,可以说是抛弃了以往的设计方式。尽管目前它的这种做法我心里还打着问号,但必定是一种尝试(不管你赞同还是不赞同)。下面就做一个简单的分析,希望能给研究MVC架构的朋友提供一些的思考。
首先要声明的是该开源项目中所使用的js就是jquery,而那些显示效果也基本上就是基于jquery中的那件插件为原型,并进行相应的属性封装,以便于在viewpage中用c#等语言进行声明绑定。下面就其中一些控件的显示截图:
在该开源项目中,所有控件均基于jQueryViewComponentBase (abstract 类型),但其自身属性并不多,而所有的控件基类属性都被jQueryViewComponentBase 的父类ViewComponentBase所定义,下面以控件中的“Accordion(属性页控件)”为例进行说明,见下图:

上图中左侧的就是ViewComponentBase类,其定义了多数控件属性,比如js脚本名称和路径以及相关样式以及最终的html元素输出方法,因为其类也是抽象类,所以其中大部分方法均为定义,而未进行具体实现。我们只要关注一下其构造方法就可以了:
<bgsound cep="0"><span style="color: #000000;"></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;">Viewcomponentbaseclass.<br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"></summary></span><span style="color: #808080;"><br></span><span style="color: #000000;"></span><span style="color: #0000ff;">public</span><span style="color: #000000;"></span><span style="color: #0000ff;">abstract</span><span style="color: #000000;"></span><span style="color: #0000ff;">class</span><span style="color: #000000;">ViewComponentBase:IStyleableComponent,IScriptableComponent<br>{<br></span><span style="color: #0000ff;">private</span><span style="color: #000000;"></span><span style="color: #0000ff;">string</span><span style="color: #000000;">name;<br><br></span><span style="color: #0000ff;">private</span><span style="color: #000000;"></span><span style="color: #0000ff;">string</span><span style="color: #000000;">styleSheetFilesLocation;<br></span><span style="color: #0000ff;">private</span><span style="color: #000000;"></span><span style="color: #0000ff;">string</span><span style="color: #000000;">scriptFilesLocation;<br><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;">初始化相关Initializesanewinstanceofthe</span><span style="color: #808080;"><seecref="ViewComponentBase"/></span><span style="color: #008000;">class.<br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"></summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><paramname="viewContext"></span><span style="color: #008000;">当前视图的上下文,将会在子类中使用</span><span style="color: #808080;"></param></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><paramname="clientSideObjectWriterFactory"></span><span style="color: #008000;">传入当前所使用的Writer工厂实例.通过子类注入,子类最终延伸到相对应的控件实例</span><span style="color: #808080;"></param></span><span style="color: #808080;"><br></span><span style="color: #000000;"></span><span style="color: #0000ff;">protected</span><span style="color: #000000;">ViewComponentBase(ViewContextviewContext,IClientSideObjectWriterFactoryclientSideObjectWriterFactory)<br>{<br>Guard.IsNotNull(viewContext,</span><span style="color: #800000;">"</span><span style="color: #800000;">viewContext</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br>Guard.IsNotNull(clientSideObjectWriterFactory,</span><span style="color: #800000;">"</span><span style="color: #800000;">clientSideObjectWriterFactory</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br><br>ViewContext</span><span style="color: #000000;">=</span><span style="color: #000000;">viewContext;<br>ClientSideObjectWriterFactory</span><span style="color: #000000;">=</span><span style="color: #000000;">clientSideObjectWriterFactory;<br><br>StyleSheetFilesPath</span><span style="color: #000000;">=</span><span style="color: #000000;">WebAssetDefaultSettings.StyleSheetFilesPath;<br>StyleSheetFileNames</span><span style="color: #000000;">=</span><span style="color: #000000;"></span><span style="color: #0000ff;">new</span><span style="color: #000000;">List</span><span style="color: #000000;"><</span><span style="color: #0000ff;">string</span><span style="color: #000000;">></span><span style="color: #000000;">();<br>ScriptFilesPath</span><span style="color: #000000;">=</span><span style="color: #000000;">WebAssetDefaultSettings.ScriptFilesPath;<br>ScriptFileNames</span><span style="color: #000000;">=</span><span style="color: #000000;"></span><span style="color: #0000ff;">new</span><span style="color: #000000;">List</span><span style="color: #000000;"><</span><span style="color: #0000ff;">string</span><span style="color: #000000;">></span><span style="color: #000000;">();<br><br>HtmlAttributes</span><span style="color: #000000;">=</span><span style="color: #000000;"></span><span style="color: #0000ff;">new</span><span style="color: #000000;">RouteValueDictionary();<br>} <br></span></bgsound>
通过上述的构造方法,就可以将控件的一些通用默认属性值进行初始化了。
下面以“Accordion”的源码来分析一下,这里还是从构造方法入手:
<bgsound cep="1"><span style="color: #0000ff;">public</span><span style="color: #000000;"></span><span style="color: #0000ff;">class</span><span style="color: #000000;">Accordion:jQueryViewComponentBase,IAccordionItemContainer<br>{<br>……<br><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;">Initializesanewinstanceofthe</span><span style="color: #808080;"><seecref="Accordion"/></span><span style="color: #008000;">class.<br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"></summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><paramname="viewContext"></span><span style="color: #008000;">Theviewcontext.</span><span style="color: #808080;"></param></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><paramname="clientSideObjectWriterFactory"></span><span style="color: #008000;">Theclientsideobjectwriterfactory.</span><span style="color: #808080;"></param></span><span style="color: #808080;"><br></span><span style="color: #000000;"></span><span style="color: #0000ff;">public</span><span style="color: #000000;">Accordion(ViewContextviewContext,IClientSideObjectWriterFactoryclientSideObjectWriterFactory):</span><span style="color: #0000ff;">base</span><span style="color: #000000;">(viewContext,clientSideObjectWriterFactory)<br>{<br>Items</span><span style="color: #000000;">=</span><span style="color: #000000;"></span><span style="color: #0000ff;">new</span><span style="color: #000000;">List</span><span style="color: #000000;"><</span><span style="color: #000000;">AccordionItem</span><span style="color: #000000;">></span><span style="color: #000000;">();<br>autoHeight</span><span style="color: #000000;">=</span><span style="color: #000000;"></span><span style="color: #0000ff;">true</span><span style="color: #000000;">;<br>} <br></span></bgsound>
注:上面的构程方法后面加入了base(viewContext, clientSideObjectWriterFactory),以实现向基类构造方法传参,也就是实现了上面所说的将当前控件所使用的viewContext,clientSideObjectWriterFactory传递到基类ViewComponentBase 中去。(注:最终的clientSideObjectWriterFactory为ClientSideObjectWriterFactory实例类型)。
当然,因为该控件的中相应属性比较简单,只是一些set,get语法,所以就不过多介绍了,相信做过控件开发的对这些再熟悉不过了。
下面主要介绍一下其write html元素时所使用的方法,如下:
<bgsound cep="2"><span style="color: #000000;"></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;">创建并写入初始化脚本对象和相应属性.<br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"></summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><paramname="writer"></span><span style="color: #008000;">Thewriter.</span><span style="color: #808080;"></param></span><span style="color: #808080;"><br></span><span style="color: #000000;"></span><span style="color: #0000ff;">public</span><span style="color: #000000;"></span><span style="color: #0000ff;">override</span><span style="color: #000000;"></span><span style="color: #0000ff;">void</span><span style="color: #000000;">WriteInitializationScript(TextWriterwriter)<br>{<br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">selectedIndex</span><span style="color: #000000;">=</span><span style="color: #000000;">Items.IndexOf(GetSelectedItem());<br><br>IClientSideObjectWriterobjectWriter</span><span style="color: #000000;">=</span><span style="color: #000000;">ClientSideObjectWriterFactory.Create(Id,</span><span style="color: #800000;">"</span><span style="color: #800000;">accordion</span><span style="color: #800000;">"</span><span style="color: #000000;">,writer);<br><br>objectWriter.Start()<br>.Append(</span><span style="color: #800000;">"</span><span style="color: #800000;">active</span><span style="color: #800000;">"</span><span style="color: #000000;">,selectedIndex,</span><span style="color: #800080;">0</span><span style="color: #000000;">)<br>.Append(</span><span style="color: #800000;">"</span><span style="color: #800000;">animated</span><span style="color: #800000;">"</span><span style="color: #000000;">,AnimationName)<br>.Append(</span><span style="color: #800000;">"</span><span style="color: #800000;">autoHeight</span><span style="color: #800000;">"</span><span style="color: #000000;">,AutoHeight,</span><span style="color: #0000ff;">true</span><span style="color: #000000;">)<br>.Append(</span><span style="color: #800000;">"</span><span style="color: #800000;">clearStyle</span><span style="color: #800000;">"</span><span style="color: #000000;">,ClearStyle,</span><span style="color: #0000ff;">false</span><span style="color: #000000;">)<br>.Append(</span><span style="color: #800000;">"</span><span style="color: #800000;">collapsible</span><span style="color: #800000;">"</span><span style="color: #000000;">,CollapsibleContent,</span><span style="color: #0000ff;">false</span><span style="color: #000000;">)<br>.Append(</span><span style="color: #800000;">"</span><span style="color: #800000;">event</span><span style="color: #800000;">"</span><span style="color: #000000;">,OpenOn)<br>.Append(</span><span style="color: #800000;">"</span><span style="color: #800000;">fillSpace</span><span style="color: #800000;">"</span><span style="color: #000000;">,FillSpace,</span><span style="color: #0000ff;">false</span><span style="color: #000000;">);<br><br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">(</span><span style="color: #000000;">!</span><span style="color: #0000ff;">string</span><span style="color: #000000;">.IsNullOrEmpty(Icon)</span><span style="color: #000000;">||</span><span style="color: #000000;"></span><span style="color: #000000;">!</span><span style="color: #0000ff;">string</span><span style="color: #000000;">.IsNullOrEmpty(SelectedIcon))<br>{<br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">(</span><span style="color: #000000;">!</span><span style="color: #0000ff;">string</span><span style="color: #000000;">.IsNullOrEmpty(Icon)</span><span style="color: #000000;">&&</span><span style="color: #000000;"></span><span style="color: #000000;">!</span><span style="color: #0000ff;">string</span><span style="color: #000000;">.IsNullOrEmpty(SelectedIcon))<br>{<br>objectWriter.Append(</span><span style="color: #800000;">"</span><span style="color: #800000;">icons:{'header':'</span><span style="color: #800000;">"</span><span style="color: #000000;"></span><span style="color: #000000;">+</span><span style="color: #000000;">Icon</span><span style="color: #000000;">+</span><span style="color: #000000;"></span><span style="color: #800000;">"</span><span style="color: #800000;">','headerSelected':'</span><span style="color: #800000;">"</span><span style="color: #000000;"></span><span style="color: #000000;">+</span><span style="color: #000000;">SelectedIcon</span><span style="color: #000000;">+</span><span style="color: #000000;"></span><span style="color: #800000;">"</span><span style="color: #800000;">'}</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br>}<br></span><span style="color: #0000ff;">else</span><span style="color: #000000;"></span><span style="color: #0000ff;">if</span><span style="color: #000000;">(</span><span style="color: #000000;">!</span><span style="color: #0000ff;">string</span><span style="color: #000000;">.IsNullOrEmpty(Icon))<br>{<br>objectWriter.Append(</span><span style="color: #800000;">"</span><span style="color: #800000;">icons:{'header':'</span><span style="color: #800000;">"</span><span style="color: #000000;"></span><span style="color: #000000;">+</span><span style="color: #000000;">Icon</span><span style="color: #000000;">+</span><span style="color: #000000;"></span><span style="color: #800000;">"</span><span style="color: #800000;">'}</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br>}<br></span><span style="color: #0000ff;">else</span><span style="color: #000000;"></span><span style="color: #0000ff;">if</span><span style="color: #000000;">(</span><span style="color: #000000;">!</span><span style="color: #0000ff;">string</span><span style="color: #000000;">.IsNullOrEmpty(SelectedIcon))<br>{<br>objectWriter.Append(</span><span style="color: #800000;">"</span><span style="color: #800000;">icons:{'headerSelected':'</span><span style="color: #800000;">"</span><span style="color: #000000;"></span><span style="color: #000000;">+</span><span style="color: #000000;">SelectedIcon</span><span style="color: #000000;">+</span><span style="color: #000000;"></span><span style="color: #800000;">"</span><span style="color: #800000;">'}</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br>}<br>}<br><br>objectWriter.Append(</span><span style="color: #800000;">"</span><span style="color: #800000;">change</span><span style="color: #800000;">"</span><span style="color: #000000;">,OnChange).Complete();<br><br></span><span style="color: #0000ff;">base</span><span style="color: #000000;">.WriteInitializationScript(writer);<br>} <br></span></bgsound>
可以看出,objectWriter (IClientSideObjectWriter 类型实例)中被绑定了相关的控件属性,并通过其类的WriteInitializationScript(writer)进行脚本的输出。而基本类的相应方法如下:
<bgsound cep="3"><span style="color: #000000;"></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;">Writestheinitializationscript.<br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"></summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><paramname="writer"></span><span style="color: #008000;">Thewriter.</span><span style="color: #808080;"></param></span><span style="color: #808080;"><br></span><span style="color: #000000;"></span><span style="color: #0000ff;">public</span><span style="color: #000000;"></span><span style="color: #0000ff;">virtual</span><span style="color: #000000;"></span><span style="color: #0000ff;">void</span><span style="color: #000000;">WriteInitializationScript(TextWriterwriter)<br>{<br>} <br></span></bgsound>
大家看到该方法为空,但其又是如何运行起来的呢,这里先卖个关子,稍后再说。接着再看一下另一个方法:WriteHtml()
<bgsound cep="4"><span style="color: #000000;"></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;">输出当前的HTML代码.<br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"></summary></span><span style="color: #808080;"><br></span><span style="color: #000000;"></span><span style="color: #0000ff;">protected</span><span style="color: #000000;"></span><span style="color: #0000ff;">override</span><span style="color: #000000;"></span><span style="color: #0000ff;">void</span><span style="color: #000000;">WriteHtml()<br>{<br>AccordionItemselectedItem</span><span style="color: #000000;">=</span><span style="color: #000000;">GetSelectedItem();<br>TextWriterwriter</span><span style="color: #000000;">=</span><span style="color: #000000;">ViewContext.HttpContext.Response.Output;<br><br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">(</span><span style="color: #000000;">!</span><span style="color: #0000ff;">string</span><span style="color: #000000;">.IsNullOrEmpty(Theme))<br>{<br>writer.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;"><divclass=\</span><span style="color: #800000;">"</span><span style="color: #000000;">{</span><span style="color: #800080;">0</span><span style="color: #000000;">}\</span><span style="color: #800000;">"</span><span style="color: #800000;">></span><span style="color: #800000;">"</span><span style="color: #000000;">.FormatWith(Theme));<br>}<br><br>HtmlAttributes.Merge(</span><span style="color: #800000;">"</span><span style="color: #800000;">id</span><span style="color: #800000;">"</span><span style="color: #000000;">,Id,</span><span style="color: #0000ff;">false</span><span style="color: #000000;">);<br>HtmlAttributes.AppendInValue(</span><span style="color: #800000;">"</span><span style="color: #800000;">class</span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #800000;">"</span><span style="color: #800000;"></span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #800000;">"</span><span style="color: #800000;">ui-accordionui-widgetui-helper-reset</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br>writer.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;"><div{0}></span><span style="color: #800000;">"</span><span style="color: #000000;">.FormatWith(HtmlAttributes.ToAttributeString()));<br><br></span><span style="color: #0000ff;">foreach</span><span style="color: #000000;">(AccordionItemitem</span><span style="color: #0000ff;">in</span><span style="color: #000000;">Items)<br>{<br>item.HtmlAttributes.AppendInValue(</span><span style="color: #800000;">"</span><span style="color: #800000;">class</span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #800000;">"</span><span style="color: #800000;"></span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #800000;">"</span><span style="color: #800000;">ui-accordion-headerui-helper-resetui-state-default</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br>item.ContentHtmlAttributes.AppendInValue(</span><span style="color: #800000;">"</span><span style="color: #800000;">class</span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #800000;">"</span><span style="color: #800000;"></span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #800000;">"</span><span style="color: #800000;">ui-accordion-contentui-helper-resetui-widget-contentui-corner-bottom</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br><br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">(item</span><span style="color: #000000;">==</span><span style="color: #000000;">selectedItem)<br>{<br>item.ContentHtmlAttributes.AppendInValue(</span><span style="color: #800000;">"</span><span style="color: #800000;">class</span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #800000;">"</span><span style="color: #800000;"></span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #800000;">"</span><span style="color: #800000;">ui-accordion-content-active</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br>}<br></span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br>{<br>item.HtmlAttributes.AppendInValue(</span><span style="color: #800000;">"</span><span style="color: #800000;">class</span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #800000;">"</span><span style="color: #800000;"></span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #800000;">"</span><span style="color: #800000;">ui-corner-all</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br>}<br><br>writer.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;"><h3{0}><ahref=\</span><span style="color: #800000;">"</span><span style="color: #000000;">#\</span><span style="color: #800000;">"</span><span style="color: #800000;">>{1}</a></h3></span><span style="color: #800000;">"</span><span style="color: #000000;">.FormatWith(item.HtmlAttributes.ToAttributeString(),item.Text));<br><br>item.ContentHtmlAttributes.AppendInValue(</span><span style="color: #800000;">"</span><span style="color: #800000;">style</span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #800000;">"</span><span style="color: #800000;">;</span><span style="color: #800000;">"</span><span style="color: #000000;">,(item</span><span style="color: #000000;">==</span><span style="color: #000000;">selectedItem)</span><span style="color: #000000;">?</span><span style="color: #000000;"></span><span style="color: #800000;">"</span><span style="color: #800000;">display:block</span><span style="color: #800000;">"</span><span style="color: #000000;">:</span><span style="color: #800000;">"</span><span style="color: #800000;">display:none</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br><br>writer.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;"><div{0}></span><span style="color: #800000;">"</span><span style="color: #000000;">.FormatWith(item.ContentHtmlAttributes.ToAttributeString()));<br>item.Content();<br>writer.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;"></div></span><span style="color: #800000;">"</span><span style="color: #000000;">);<br>}<br><br>writer.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;"></div></span><span style="color: #800000;">"</span><span style="color: #000000;">);<br><br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">(</span><span style="color: #000000;">!</span><span style="color: #0000ff;">string</span><span style="color: #000000;">.IsNullOrEmpty(Theme))<br>{<br>writer.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;"></div></span><span style="color: #800000;">"</span><span style="color: #000000;">);<br>}<br><br></span><span style="color: #0000ff;">base</span><span style="color: #000000;">.WriteHtml();<br>} <br></span></bgsound>
该方法首先获取当前所选属性页标签(GetSelectedItem()方法),然后用foreach方法对属性页标签集合进行遍历,并判断当前属性页是否就是被选中的属性页,并绑定上相应的css属性。其最终也是调用相应的基类方法进行输出。当然这里基类方法也是为空,呵呵。
准备好了这个控件类之后,Telerik还为Accordion控件‘准备’了一些辅助组件,比如属性页组件(AccordionItem),以及相关的组件构造器(AccordionItemBuilder,AccordionBuilder),这样我们就可以通过这些构造器很方便的创建相应的控件和组件了,下面就以AccordionItemBuilder为例,解释一下其构造器结构:
Code
<bgsound cep="5"><span style="color: #0000ff;">public</span><span style="color: #000000;"></span><span style="color: #0000ff;">class</span><span style="color: #000000;">AccordionBuilder:ViewComponentBuilderBase</span><span style="color: #000000;"><</span><span style="color: #000000;">Accordion,AccordionBuilder</span><span style="color: #000000;">></span><span style="color: #000000;">,IHideObjectMembers<br>{<br><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;">初始化方法Initializesanewinstanceofthe</span><span style="color: #808080;"><seecref="AccordionBuilder"/></span><span style="color: #008000;">class.<br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"></summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><paramname="component"></span><span style="color: #008000;">Thecomponent.</span><span style="color: #808080;"></param></span><span style="color: #808080;"><br></span><span style="color: #000000;"></span><span style="color: #0000ff;">public</span><span style="color: #000000;">AccordionBuilder(Accordioncomponent):</span><span style="color: #0000ff;">base</span><span style="color: #000000;">(component)<br>{}<br><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;">指定一个属性页选项<br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"></summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><paramname="addAction"></span><span style="color: #008000;">要添加的action.</span><span style="color: #808080;"></param></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><returns></returns></span><span style="color: #808080;"><br></span><span style="color: #000000;"></span><span style="color: #0000ff;">public</span><span style="color: #000000;"></span><span style="color: #0000ff;">virtual</span><span style="color: #000000;">AccordionBuilderItems(Action</span><span style="color: #000000;"><</span><span style="color: #000000;">AccordionItemFactory</span><span style="color: #000000;">></span><span style="color: #000000;">addAction)<br>{<br>Guard.IsNotNull(addAction,</span><span style="color: #800000;">"</span><span style="color: #800000;">addAction</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br><br>AccordionItemFactoryfactory</span><span style="color: #000000;">=</span><span style="color: #000000;"></span><span style="color: #0000ff;">new</span><span style="color: #000000;">AccordionItemFactory(Component);<br><br>addAction(factory);<br><br></span><span style="color: #0000ff;">return</span><span style="color: #000000;"></span><span style="color: #0000ff;">this</span><span style="color: #000000;">;<br>}<br><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;">属性页动态效果显示名称(鼠标在属性页移入移出时)<br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"></summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><paramname="effectName"></span><span style="color: #008000;">Nameoftheeffect.</span><span style="color: #808080;"></param></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><returns></returns></span><span style="color: #808080;"><br></span><span style="color: #000000;"></span><span style="color: #0000ff;">public</span><span style="color: #000000;"></span><span style="color: #0000ff;">virtual</span><span style="color: #000000;">AccordionBuilderAnimate(</span><span style="color: #0000ff;">string</span><span style="color: #000000;">effectName)<br>{<br>Component.AnimationName</span><span style="color: #000000;">=</span><span style="color: #000000;">effectName;<br><br></span><span style="color: #0000ff;">return</span><span style="color: #000000;"></span><span style="color: #0000ff;">this</span><span style="color: #000000;">;<br>}<br><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;">是否高度自适用.<br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"></summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><paramname="value"></span><span style="color: #008000;">ifsetto</span><span style="color: #808080;"><c></span><span style="color: #008000;">true</span><span style="color: #808080;"></c></span><span style="color: #008000;">value.</span><span style="color: #808080;"></param></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><returns></returns></span><span style="color: #808080;"><br></span><span style="color: #000000;"></span><span style="color: #0000ff;">public</span><span style="color: #000000;"></span><span style="color: #0000ff;">virtual</span><span style="color: #000000;">AccordionBuilderAutoHeight(</span><span style="color: #0000ff;">bool</span><span style="color: #000000;">value)<br>{<br>Component.AutoHeight</span><span style="color: #000000;">=</span><span style="color: #000000;">value;<br><br></span><span style="color: #0000ff;">return</span><span style="color: #000000;"></span><span style="color: #0000ff;">this</span><span style="color: #000000;">;<br>}<br><br><br><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;">指定要触发的属性页事件名称.<br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"></summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><paramname="eventName"></span><span style="color: #008000;">Nameoftheevent.</span><span style="color: #808080;"></param></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><returns></returns></span><span style="color: #808080;"><br></span><span style="color: #000000;"></span><span style="color: #0000ff;">public</span><span style="color: #000000;"></span><span style="color: #0000ff;">virtual</span><span style="color: #000000;">AccordionBuilderOpenOn(</span><span style="color: #0000ff;">string</span><span style="color: #000000;">eventName)<br>{<br>Component.OpenOn</span><span style="color: #000000;">=</span><span style="color: #000000;">eventName;<br><br></span><span style="color: #0000ff;">return</span><span style="color: #000000;"></span><span style="color: #0000ff;">this</span><span style="color: #000000;">;<br>}<br><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;">所使用的Icons名称.<br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"></summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><paramname="name"></span><span style="color: #008000;">Thename.</span><span style="color: #808080;"></param></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><returns></returns></span><span style="color: #808080;"><br></span><span style="color: #000000;"></span><span style="color: #0000ff;">public</span><span style="color: #000000;"></span><span style="color: #0000ff;">virtual</span><span style="color: #000000;">AccordionBuilderIcon(</span><span style="color: #0000ff;">string</span><span style="color: #000000;">name)<br>{<br>Component.Icon</span><span style="color: #000000;">=</span><span style="color: #000000;">name;<br><br></span><span style="color: #0000ff;">return</span><span style="color: #000000;"></span><span style="color: #0000ff;">this</span><span style="color: #000000;">;<br>}<br><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;">被选中的属性页所使用的Icons名称<br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"></summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><paramname="name"></span><span style="color: #008000;">Thename.</span><span style="color: #808080;"></param></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><returns></returns></span><span style="color: #808080;"><br></span><span style="color: #000000;"></span><span style="color: #0000ff;">public</span><span style="color: #000000;"></span><span style="color: #0000ff;">virtual</span><span style="color: #000000;">AccordionBuilderSelectedIcon(</span><span style="color: #0000ff;">string</span><span style="color: #000000;">name)<br>{<br>Component.SelectedIcon</span><span style="color: #000000;">=</span><span style="color: #000000;">name;<br><br></span><span style="color: #0000ff;">return</span><span style="color: #000000;"></span><span style="color: #0000ff;">this</span><span style="color: #000000;">;<br>}<br><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;">当属性页发生变化时要传递的action脚本.<br><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"></summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><paramname="javaScript"></span><span style="color: #008000;">Thejavascript.</span><span style="color: #808080;"></param></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><returns></returns></span><span style="color: #808080;"><br></span><span style="color: #000000;"></span><span style="color: #0000ff;">public</span><span style="color: #000000;"></span><span style="color: #0000ff;">virtual</span><span style="color: #000000;">AccordionBuilderOnChange(ActionjavaScript)<br>{<br>Component.OnChange</span><span style="color: #000000;">=</span><span style="color: #000000;">javaScript;<br><br></span><span style="color: #0000ff;">return</span><span style="color: #000000;"></span><span style="color: #0000ff;">this</span><span style="color: #000000;">;<br>}<br><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;">Specifythenameofthethemeappliestotheaccordion.<br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"></summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><paramname="name"></span><span style="color: #008000;">Thename.</span><span style="color: #808080;"></param></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><returns></returns></span><span style="color: #808080;"><br></span><span style="color: #000000;"></span><span style="color: #0000ff;">public</span><span style="color: #000000;"></span><span style="color: #0000ff;">virtual</span><span style="color: #000000;">AccordionBuilderTheme(</span><span style="color: #0000ff;">string</span><span style="color: #000000;">name)<br>{<br>Component.Theme</span><span style="color: #000000;">=</span><span style="color: #000000;">name;<br><br></span><span style="color: #0000ff;">return</span><span style="color: #000000;"></span><span style="color: #0000ff;">this</span><span style="color: #000000;">;<br>}<br>}</span></bgsound>
对于上面的OnChange方法,可以使用下面的方法将相应的js脚本传入并执行
<bgsound cep="6"><span style="color: #000000;">.OnChange(()</span><span style="color: #000000;">=></span><span style="color: #000000;"><br>{</span><span style="color: #000000;">%></span><span style="color: #000000;"><br>function(</span><span style="color: #0000ff;">event</span><span style="color: #000000;">,ui)<br>{<br>$(</span><span style="color: #800000;">'</span><span style="color: #800000;">#trace</span><span style="color: #800000;">'</span><span style="color: #000000;">).append(</span><span style="color: #800000;">'</span><span style="color: #800000;">Changefired:</span><span style="color: #800000;">'</span><span style="color: #000000;"></span><span style="color: #000000;">+</span><span style="color: #000000;"></span><span style="color: #0000ff;">new</span><span style="color: #000000;">Date()</span><span style="color: #000000;">+</span><span style="color: #000000;"></span><span style="color: #800000;">'</span><span style="color: #800000;"><br/></span><span style="color: #800000;">'</span><span style="color: #000000;">);<br>}<br></span><span style="color: #000000;"><%</span><span style="color: #000000;">}<br>) <br></span></bgsound>
这样,当属性页发生变化时,就会在页面的指定区域将变化时间显示出来了,如下图:
Telerik在jQueryViewComponentFactory中对项目中每一个控件提供了一个方法用以初始化相应的构造器,以便于创建相应的控件,比如Accordion,形如:
<bgsound cep="7"><span style="color: #000000;"></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;">CreatesaaccordionforASP.NETMVCview.<br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"></summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><returns></returns></span><span style="color: #808080;"><br></span><span style="color: #000000;">[DebuggerStepThrough]<br></span><span style="color: #0000ff;">public</span><span style="color: #000000;"></span><span style="color: #0000ff;">virtual</span><span style="color: #000000;">AccordionBuilderAccordion()<br>{<br></span><span style="color: #0000ff;">return</span><span style="color: #000000;"></span><span style="color: #0000ff;">new</span><span style="color: #000000;">AccordionBuilder(Create(()</span><span style="color: #000000;">=></span><span style="color: #000000;"></span><span style="color: #0000ff;">new</span><span style="color: #000000;">Accordion(ViewContext,clientSideObjectWriterFactory)));<br>} <br></span></bgsound>
而对于其在VIEW中的使用,则通过扩展方法来加以声明:
<bgsound cep="8"><span style="color: #0000ff;">public</span><span style="color: #000000;"></span><span style="color: #0000ff;">static</span><span style="color: #000000;"></span><span style="color: #0000ff;">class</span><span style="color: #000000;">HtmlHelperExtension<br>{<br></span><span style="color: #0000ff;">private</span><span style="color: #000000;"></span><span style="color: #0000ff;">static</span><span style="color: #000000;"></span><span style="color: #0000ff;">readonly</span><span style="color: #000000;">IClientSideObjectWriterFactoryfactory</span><span style="color: #000000;">=</span><span style="color: #000000;"></span><span style="color: #0000ff;">new</span><span style="color: #000000;">ClientSideObjectWriterFactory();<br><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;">GetsthejQueryviewcomponentsinstance.<br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"></summary></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><paramname="helper"></span><span style="color: #008000;">Thehtmlhelper.</span><span style="color: #808080;"></param></span><span style="color: #008000;"><br></span><span style="color: #808080;">///</span><span style="color: #008000;"></span><span style="color: #808080;"><returns></span><span style="color: #008000;">jQueryViewComponentFactory</span><span style="color: #808080;"></returns></span><span style="color: #808080;"><br></span><span style="color: #000000;">[DebuggerStepThrough]<br></span><span style="color: #0000ff;">public</span><span style="color: #000000;"></span><span style="color: #0000ff;">static</span><span style="color: #000000;">jQueryViewComponentFactoryjQuery(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">HtmlHelperhelper)<br>{<br></span><span style="color: #0000ff;">return</span><span style="color: #000000;"></span><span style="color: #0000ff;">new</span><span style="color: #000000;">jQueryViewComponentFactory(helper,factory);<br>}<br>} <br></span></bgsound>
这样在页面视图中,我们这可以使用下面的写法来构造一个Accordion控件了:
<bgsound cep="9"><span style="color: #000000;"><%</span><span style="color: #000000;">Html.jQuery().Accordion()<br>.Name(</span><span style="color: #800000;">"</span><span style="color: #800000;">myAccordion</span><span style="color: #800000;">"</span><span style="color: #000000;">)<br>.Animate(</span><span style="color: #800000;">"</span><span style="color: #800000;">bounceslide</span><span style="color: #800000;">"</span><span style="color: #000000;">)<br>.Items(parent</span><span style="color: #000000;">=></span><span style="color: #000000;"><br><br>…… <br></span></bgsound>
上面只是介绍了前台和底层代码如果显示的问题,但还没有解释之前所说的WriteInitializationScript(TextWriter writer)方法以及WriteHtml()
方法如何被调用的问题,正如之前所看到的,因为Accordion的基类ViewComponentBase中未实现具体的代码,所以这里我们要将注意力转移到 jQueryViewComponentFactory中,请看如下代码:
<bgsound cep="10"><span style="color: #0000ff;">private</span><span style="color: #000000;">TViewComponentCreate</span><span style="color: #000000;"><</span><span style="color: #000000;">TViewComponent</span><span style="color: #000000;">></span><span style="color: #000000;">(Func</span><span style="color: