一个Asp.net MVC 控件项目分析---Telerik.Web.Mvc
2009-09-09 08:36
661 查看
body {padding:0;margin:0;} 在写本文之前,本人一直抱着‘不宜’在asp.net MVC框架下搞什么控件开发的想法,因为一提到控件就会让人想起‘事件’,‘VIEWSTATE’等一些问题,而asp.net MVC下是Controller, Action, Viewpage, Filter等特性的‘天下’。所以总感觉‘驴唇对不上马嘴’。
但直到前阵子在邮箱中收到了关于telerik关于MVC框架扩展的一些信息之后,才发现这家商业控件公司也开始打MVC的主意了。而这个项目(开源)就是该公司在理解了asp.net mvc的基础上所做的一些尝试,当然其所实现的所谓控件与之前我们在项目中所开发或使用的web服务器控件有很大的不同,可以说是抛弃了以往的设计方式。尽管目前它的这种做法我心里还打着问号,但必定是一种尝试(不管你赞同还是不赞同)。下面就做一个简单的分析,希望能给研究MVC架构的朋友提供一些的思考。
首先要声明的是该开源项目中所使用的js就是jquery,而那些显示效果也基本上就是基于jquery中的那件插件为原型,并进行相应的属性封装,以便于在viewpage中用c#等语言进行声明绑定。下面就其中一些控件的显示截图:
public class AccordionBuilder : ViewComponentBuilderBase<Accordion, AccordionBuilder>, IHideObjectMembers
{
/// <summary>
/// 初始化方法Initializes a new instance of the <see cref="AccordionBuilder"/> class.
/// </summary>
/// <param name="component">The component.</param>
public AccordionBuilder(Accordion component) : base(component)
{}
/// <summary>
/// 指定一个属性页选项
/// </summary>
/// <param name="addAction">要添加的action.</param>
/// <returns></returns>
public virtual AccordionBuilder Items(Action<AccordionItemFactory> addAction)
{
Guard.IsNotNull(addAction, "addAction");
AccordionItemFactory factory = new AccordionItemFactory(Component);
addAction(factory);
return this;
}
/// <summary>
/// 属性页动态效果显示名称(鼠标在属性页移入移出时)
/// </summary>
/// <param name="effectName">Name of the effect.</param>
/// <returns></returns>
public virtual AccordionBuilder Animate(string effectName)
{
Component.AnimationName = effectName;
return this;
}
/// <summary>
/// 是否高度自适用.
/// </summary>
/// <param name="value">if set to <c>true</c> value.</param>
/// <returns></returns>
public virtual AccordionBuilder AutoHeight(bool value)
{
Component.AutoHeight = value;
return this;
}
/// <summary>
/// 指定要触发的属性页事件名称.
/// </summary>
/// <param name="eventName">Name of the event.</param>
/// <returns></returns>
public virtual AccordionBuilder OpenOn(string eventName)
{
Component.OpenOn = eventName;
return this;
}
/// <summary>
/// 所使用的Icons名称.
/// </summary>
/// <param name="name">The name.</param>
/// <returns></returns>
public virtual AccordionBuilder Icon(string name)
{
Component.Icon = name;
return this;
}
/// <summary>
/// 被选中的属性页所使用的Icons 名称
/// </summary>
/// <param name="name">The name.</param>
/// <returns></returns>
public virtual AccordionBuilder SelectedIcon(string name)
{
Component.SelectedIcon = name;
return this;
}
/// <summary>
/// 当属性页发生变化时要传递的action 脚本.
/// </summary>
/// <param name="javaScript">The java script.</param>
/// <returns></returns>
public virtual AccordionBuilder OnChange(Action javaScript)
{
Component.OnChange = javaScript;
return this;
}
/// <summary>
/// Specify the name of the theme applies to the accordion.
/// </summary>
/// <param name="name">The name.</param>
/// <returns></returns>
public virtual AccordionBuilder Theme(string name)
{
Component.Theme = name;
return this;
}
}
对于上面的OnChange方法,可以使用下面的方法将相应的js脚本传入并执行
.OnChange(() =>
{%>
function(event, ui)
{
$('#trace').append('Change fired: ' + new Date() + '<br/>');
}
<%}
)
这样,当属性页发生变化时,就会在页面的指定区域将变化时间显示出来了,如下图:
![](http://images.cnblogs.com/cnblogs_com/daizhj/WindowsLiveWriter/Asp.netMVCtelerik_C16B/telerik_mvc_onchange_thumb.gif)
Telerik在jQueryViewComponentFactory中对项目中每一个控件提供了一个方法用以初始化相应的构造器,以便于创建相应的控件,比如Accordion,形如:
/// <summary>
/// Creates a accordion for ASP.NET MVC view.
/// </summary>
/// <returns></returns>
[DebuggerStepThrough]
public virtual AccordionBuilder Accordion()
{
return new AccordionBuilder(Create(() => new Accordion(ViewContext, clientSideObjectWriterFactory)));
}
而对于其在VIEW中的使用,则通过扩展方法来加以声明:
public static class HtmlHelperExtension
{
private static readonly IClientSideObjectWriterFactory factory = new ClientSideObjectWriterFactory();
/// <summary>
/// Gets the jQuery view components instance.
/// </summary>
/// <param name="helper">The html helper.</param>
/// <returns>jQueryViewComponentFactory</returns>
[DebuggerStepThrough]
public static jQueryViewComponentFactory jQuery(this HtmlHelper helper)
{
return new jQueryViewComponentFactory(helper, factory);
}
}
这样在页面视图中,我们这可以使用下面的写法来构造一个Accordion控件了:
<% Html.jQuery().Accordion()
.Name("myAccordion")
.Animate("bounceslide")
.Items(parent =>
……
上面只是介绍了前台和底层代码如果显示的问题,但还没有解释之前所说的WriteInitializationScript(TextWriter writer)方法以及WriteHtml()
方法如何被调用的问题,正如之前所看到的,因为Accordion的基类ViewComponentBase中未实现具体的代码,所以这里我们要将注意力转移到 jQueryViewComponentFactory中,请看如下代码:
private TViewComponent Create<TViewComponent>(Func<TViewComponent> factory) where TViewComponent : ViewComponentBase
{
TViewComponent component = factory();
if (component is jQueryViewComponentBase)
{
component.AssetKey = DefaultAssetKey;
}
htmlHelper.Telerik().StyleSheetRegistrar().ToRegistrar().Register(component);
htmlHelper.Telerik().ScriptRegistrar().ToRegistrar().Register(component);
return component;
}
上面的方法其实就是之前在该类方法Accordion()中所调用并执行的:
return new AccordionBuilder(Create(() => new Accordion(ViewContext, clientSideObjectWriterFactory)));
通过该方法,就可以将该控件及其相关组件信息注册到相应的视图中。因为我们比较关注WriteHtml()方法,所以这里就直接分析一下这一行代码:
ScriptRegistrar().ToRegistrar().Register(component);
ScriptRegistrar类中的Register方法承担着将当前要创建的组件添加到当前的脚本组件列表中的任务(scriptableComponents为list列表)
/// <summary>
/// Registers the scriptable component.
/// </summary>
/// <param name="component">The component.</param>
public virtual void Register(IScriptableComponent component)
{
Guard.IsNotNull(component, "component");
if (!scriptableComponents.Contains(component))
{
scriptableComponents.Add(component);
}
}
当组件被成功添加到该list列表中后,系统就会调用Render()方法将其显示出来(注:该方法与以前web控件开发中的显示方法同名,所以比较好理解),如下:
/// <summary>
/// Writes the scripts in the response.
/// </summary>
public void Render()
{
if (hasRendered)
{
throw new InvalidOperationException(Resources.TextResource.YouCannotCallRenderMoreThanOnce);
}
if (ViewContext.HttpContext.Request.Browser.EcmaScriptVersion.Major >= 1)
{
Write(ViewContext.HttpContext.Response.Output);
}
hasRendered = true;
}
注意上面的这一行代码:
Write(ViewContext.HttpContext.Response.Output);
其所实现的功能如下:
/// <summary>
/// 写出所有脚本资源和脚本 statements.
/// </summary>
/// <param name="writer">The writer.</param>
protected virtual void Write(TextWriter writer)
{
WriteScriptSources(writer);
WriteScriptStatements(writer);
}
而就是WriteScriptStatements这行代码开始执行之前所说的那个WriteInitializationScript(TextWriter writer)。而WriteHtml()方法的执行入口要更加复杂一些,因为Telerik提供了ViewComponentBuilderBase这个类来进行视图组件的构造,而该类中的Render方法就是对相应组件的Render方法(组件中已定义)进行调用,如下:
/// <summary>
/// Renders the component.
/// </summary>
public virtual void Render()
{
Component.Render();
}
而之前的“Accordion”控件是继承自ViewComponentBase类,所以相应组件的Render方法就在该类中进行了声明定义,如下:
/// <summary>
/// Renders the component.
/// </summary>
public void Render()
{
EnsureRequired();
WriteHtml();
}
大家看到了第二行代码了吧,这就是我们之前看到的那个方法,也就是Accordion组件中WriteHtml()重写方法的调用入口。
绕了这么一大圈,才把这个流程理清,是不是有些晕了。的确,刚开始接触时我也有点晕,但晕呀晕呀就‘晕过去了’,现在再回头看起来感常见其整体的架构思路还是很清晰的。可以说有了这瓶酒垫底,再分析该项目中的其它控件就‘如鱼得水’了。
最后不妨总结一下:
该项目中对asp.net mvc控件下的开发做了一次尝试,但如果之前做过控件特别是web服务器端控件开发的朋友,可以看出项目中有非常重的web控件开发味道,基本连方法名称都有一定的重叠。
另外就是其自身还是引用了组件对象模型的概念,就拿属性页控件来说,就将其分为Accordion和AccordionItem两种类型,其中可以将Accordion看成是AccordionItem的集合封装(包括遍历操作),而这里AccordionItem就成了Accordion的一个组件,而Accordion又是当前view中的一个组件。而组件开发一直是.net平台上所倡导的。其优势在于可复用,维护方便,简化复杂问题等。
好了,今天的内容就先到这里了。
原文链接:http://www.cnblogs.com/daizhj/archive/2009/09/09/1562966.html
作者: daizhj, 代震军
Tags: asp.net,mvc,component,组件,控件,Telerik
网址: http://daizhj.cnblogs.com/
但直到前阵子在邮箱中收到了关于telerik关于MVC框架扩展的一些信息之后,才发现这家商业控件公司也开始打MVC的主意了。而这个项目(开源)就是该公司在理解了asp.net mvc的基础上所做的一些尝试,当然其所实现的所谓控件与之前我们在项目中所开发或使用的web服务器控件有很大的不同,可以说是抛弃了以往的设计方式。尽管目前它的这种做法我心里还打着问号,但必定是一种尝试(不管你赞同还是不赞同)。下面就做一个简单的分析,希望能给研究MVC架构的朋友提供一些的思考。
首先要声明的是该开源项目中所使用的js就是jquery,而那些显示效果也基本上就是基于jquery中的那件插件为原型,并进行相应的属性封装,以便于在viewpage中用c#等语言进行声明绑定。下面就其中一些控件的显示截图:
public class AccordionBuilder : ViewComponentBuilderBase<Accordion, AccordionBuilder>, IHideObjectMembers
{
/// <summary>
/// 初始化方法Initializes a new instance of the <see cref="AccordionBuilder"/> class.
/// </summary>
/// <param name="component">The component.</param>
public AccordionBuilder(Accordion component) : base(component)
{}
/// <summary>
/// 指定一个属性页选项
/// </summary>
/// <param name="addAction">要添加的action.</param>
/// <returns></returns>
public virtual AccordionBuilder Items(Action<AccordionItemFactory> addAction)
{
Guard.IsNotNull(addAction, "addAction");
AccordionItemFactory factory = new AccordionItemFactory(Component);
addAction(factory);
return this;
}
/// <summary>
/// 属性页动态效果显示名称(鼠标在属性页移入移出时)
/// </summary>
/// <param name="effectName">Name of the effect.</param>
/// <returns></returns>
public virtual AccordionBuilder Animate(string effectName)
{
Component.AnimationName = effectName;
return this;
}
/// <summary>
/// 是否高度自适用.
/// </summary>
/// <param name="value">if set to <c>true</c> value.</param>
/// <returns></returns>
public virtual AccordionBuilder AutoHeight(bool value)
{
Component.AutoHeight = value;
return this;
}
/// <summary>
/// 指定要触发的属性页事件名称.
/// </summary>
/// <param name="eventName">Name of the event.</param>
/// <returns></returns>
public virtual AccordionBuilder OpenOn(string eventName)
{
Component.OpenOn = eventName;
return this;
}
/// <summary>
/// 所使用的Icons名称.
/// </summary>
/// <param name="name">The name.</param>
/// <returns></returns>
public virtual AccordionBuilder Icon(string name)
{
Component.Icon = name;
return this;
}
/// <summary>
/// 被选中的属性页所使用的Icons 名称
/// </summary>
/// <param name="name">The name.</param>
/// <returns></returns>
public virtual AccordionBuilder SelectedIcon(string name)
{
Component.SelectedIcon = name;
return this;
}
/// <summary>
/// 当属性页发生变化时要传递的action 脚本.
/// </summary>
/// <param name="javaScript">The java script.</param>
/// <returns></returns>
public virtual AccordionBuilder OnChange(Action javaScript)
{
Component.OnChange = javaScript;
return this;
}
/// <summary>
/// Specify the name of the theme applies to the accordion.
/// </summary>
/// <param name="name">The name.</param>
/// <returns></returns>
public virtual AccordionBuilder Theme(string name)
{
Component.Theme = name;
return this;
}
}
对于上面的OnChange方法,可以使用下面的方法将相应的js脚本传入并执行
.OnChange(() =>
{%>
function(event, ui)
{
$('#trace').append('Change fired: ' + new Date() + '<br/>');
}
<%}
)
这样,当属性页发生变化时,就会在页面的指定区域将变化时间显示出来了,如下图:
![](http://images.cnblogs.com/cnblogs_com/daizhj/WindowsLiveWriter/Asp.netMVCtelerik_C16B/telerik_mvc_onchange_thumb.gif)
Telerik在jQueryViewComponentFactory中对项目中每一个控件提供了一个方法用以初始化相应的构造器,以便于创建相应的控件,比如Accordion,形如:
/// <summary>
/// Creates a accordion for ASP.NET MVC view.
/// </summary>
/// <returns></returns>
[DebuggerStepThrough]
public virtual AccordionBuilder Accordion()
{
return new AccordionBuilder(Create(() => new Accordion(ViewContext, clientSideObjectWriterFactory)));
}
而对于其在VIEW中的使用,则通过扩展方法来加以声明:
public static class HtmlHelperExtension
{
private static readonly IClientSideObjectWriterFactory factory = new ClientSideObjectWriterFactory();
/// <summary>
/// Gets the jQuery view components instance.
/// </summary>
/// <param name="helper">The html helper.</param>
/// <returns>jQueryViewComponentFactory</returns>
[DebuggerStepThrough]
public static jQueryViewComponentFactory jQuery(this HtmlHelper helper)
{
return new jQueryViewComponentFactory(helper, factory);
}
}
这样在页面视图中,我们这可以使用下面的写法来构造一个Accordion控件了:
<% Html.jQuery().Accordion()
.Name("myAccordion")
.Animate("bounceslide")
.Items(parent =>
……
上面只是介绍了前台和底层代码如果显示的问题,但还没有解释之前所说的WriteInitializationScript(TextWriter writer)方法以及WriteHtml()
方法如何被调用的问题,正如之前所看到的,因为Accordion的基类ViewComponentBase中未实现具体的代码,所以这里我们要将注意力转移到 jQueryViewComponentFactory中,请看如下代码:
private TViewComponent Create<TViewComponent>(Func<TViewComponent> factory) where TViewComponent : ViewComponentBase
{
TViewComponent component = factory();
if (component is jQueryViewComponentBase)
{
component.AssetKey = DefaultAssetKey;
}
htmlHelper.Telerik().StyleSheetRegistrar().ToRegistrar().Register(component);
htmlHelper.Telerik().ScriptRegistrar().ToRegistrar().Register(component);
return component;
}
上面的方法其实就是之前在该类方法Accordion()中所调用并执行的:
return new AccordionBuilder(Create(() => new Accordion(ViewContext, clientSideObjectWriterFactory)));
通过该方法,就可以将该控件及其相关组件信息注册到相应的视图中。因为我们比较关注WriteHtml()方法,所以这里就直接分析一下这一行代码:
ScriptRegistrar().ToRegistrar().Register(component);
ScriptRegistrar类中的Register方法承担着将当前要创建的组件添加到当前的脚本组件列表中的任务(scriptableComponents为list列表)
/// <summary>
/// Registers the scriptable component.
/// </summary>
/// <param name="component">The component.</param>
public virtual void Register(IScriptableComponent component)
{
Guard.IsNotNull(component, "component");
if (!scriptableComponents.Contains(component))
{
scriptableComponents.Add(component);
}
}
当组件被成功添加到该list列表中后,系统就会调用Render()方法将其显示出来(注:该方法与以前web控件开发中的显示方法同名,所以比较好理解),如下:
/// <summary>
/// Writes the scripts in the response.
/// </summary>
public void Render()
{
if (hasRendered)
{
throw new InvalidOperationException(Resources.TextResource.YouCannotCallRenderMoreThanOnce);
}
if (ViewContext.HttpContext.Request.Browser.EcmaScriptVersion.Major >= 1)
{
Write(ViewContext.HttpContext.Response.Output);
}
hasRendered = true;
}
注意上面的这一行代码:
Write(ViewContext.HttpContext.Response.Output);
其所实现的功能如下:
/// <summary>
/// 写出所有脚本资源和脚本 statements.
/// </summary>
/// <param name="writer">The writer.</param>
protected virtual void Write(TextWriter writer)
{
WriteScriptSources(writer);
WriteScriptStatements(writer);
}
而就是WriteScriptStatements这行代码开始执行之前所说的那个WriteInitializationScript(TextWriter writer)。而WriteHtml()方法的执行入口要更加复杂一些,因为Telerik提供了ViewComponentBuilderBase这个类来进行视图组件的构造,而该类中的Render方法就是对相应组件的Render方法(组件中已定义)进行调用,如下:
/// <summary>
/// Renders the component.
/// </summary>
public virtual void Render()
{
Component.Render();
}
而之前的“Accordion”控件是继承自ViewComponentBase类,所以相应组件的Render方法就在该类中进行了声明定义,如下:
/// <summary>
/// Renders the component.
/// </summary>
public void Render()
{
EnsureRequired();
WriteHtml();
}
大家看到了第二行代码了吧,这就是我们之前看到的那个方法,也就是Accordion组件中WriteHtml()重写方法的调用入口。
绕了这么一大圈,才把这个流程理清,是不是有些晕了。的确,刚开始接触时我也有点晕,但晕呀晕呀就‘晕过去了’,现在再回头看起来感常见其整体的架构思路还是很清晰的。可以说有了这瓶酒垫底,再分析该项目中的其它控件就‘如鱼得水’了。
最后不妨总结一下:
该项目中对asp.net mvc控件下的开发做了一次尝试,但如果之前做过控件特别是web服务器端控件开发的朋友,可以看出项目中有非常重的web控件开发味道,基本连方法名称都有一定的重叠。
另外就是其自身还是引用了组件对象模型的概念,就拿属性页控件来说,就将其分为Accordion和AccordionItem两种类型,其中可以将Accordion看成是AccordionItem的集合封装(包括遍历操作),而这里AccordionItem就成了Accordion的一个组件,而Accordion又是当前view中的一个组件。而组件开发一直是.net平台上所倡导的。其优势在于可复用,维护方便,简化复杂问题等。
好了,今天的内容就先到这里了。
原文链接:http://www.cnblogs.com/daizhj/archive/2009/09/09/1562966.html
作者: daizhj, 代震军
Tags: asp.net,mvc,component,组件,控件,Telerik
网址: http://daizhj.cnblogs.com/
相关文章推荐
- 一个Asp.net MVC 控件项目分析---Telerik.Web.Mvc
- 一个Asp.net MVC 控件项目分析---Telerik.Web.Mvc
- 一个Asp.net MVC 控件项目分析---Telerik.Web.Mvc 推荐
- Asp.net 2.0 自定义控件开发[开发一个图表(WebChart)控件(柱状图示例)](示例代码下载)
- Asp.net MVC 示例项目"Suteki.Shop"分析之---NVelocity模版引擎
- Asp.net MVC 示例项目"Suteki.Shop"分析之---NVelocity模版引擎 (转)
- Asp.net MVC 示例项目"Suteki.Shop"分析之---NHibernate
- 一个小Forum Web程序示例,ASP.NET MVC Framework,总体结构介绍(Part 1)
- Asp.net 2.0 自定义控件开发[开发一个图表(WebChart)控件(柱状图示例)](示例代码下载)
- Asp.net MVC 示例项目"Suteki.Shop"分析之---ViewData
- Asp.net MVC 示例项目"Suteki.Shop"分析之---IOC(控制反转)
- 【分享】一个Asp.net mvc下的分页控件MvcPagerX
- Telerik Extensions for ASP.NET MVC 中文教程(2) - 在项目中引用Telerik MVC Extensions
- Asp.net MVC 示例项目"Suteki.Shop"分析之---安装篇 推荐
- 控件中国网:WebGrid.NET Enterprise®,一个为ASP.NET平台下WEB开发而设计的高级数据表格控件。(最新版本发布)
- ASP.NET MVC 1.0 - 2. 流程分析 (System.Web.Routing)
- 如何使用 asp.net 4.0 新特性 路由功能 有助于seo优化 给一个 asp.net web项目(网站项目) 增加路由功能 ,继承,给根据路由生成的url的结尾,增加一个有利于seo优化的斜杠 /,跳转到一个路由生成的url页面
- ASP.NET MVC 4新建库项目中找不到 System.Web.Security 的引用
- ASP.NET MVC 1.0 流程分析(System.Web.Routing)【zz】
- VS2013 ASP.NET MVC 修改Web项目的IISExpress的端口固定