带你读开源—ASP.NET_MVC(十一)

来源:互联网 发布:如何开农村淘宝店 编辑:程序博客网 时间:2024/05/16 06:49

        上篇说到HtmlHelper,今天继续这个话题。

        我们在自己建立的MVC项目中,随便打开一个.cshtml文件,找到一个HtmlHelper调用,例如:@Html.TextBox("CustomerName"),把光标放在Html上,按F12进入其定义,即代码段1中的语句【public new HtmlHelper<TModel> Html { get; set; }】。可见,@Html是HtmlHelper<TModel>类的一个实例,并且它是泛型类WebViewPage<TModel>的一个属性,由于.cshtml文件中的类继承于泛型类WebViewPage<TModel>,所以我们在Razor中可以直接使用@Html。

#region 程序集System.Web.Mvc.dll, v4.0.30319// C:\Program Files(x86)\Microsoft ASP.NET\ASP.NET MVC 4\Assemblies\System.Web.Mvc.dll#endregion using System; namespace System.Web.Mvc{    // 摘要:    //    表示呈现使用 ASP.NET Razor 语法的视图所需的属性和方法。    //    // 类型参数:    //  TModel:    //    视图数据模型的类型。    public abstract classWebViewPage<TModel> : WebViewPage    {        // 摘要:        //    初始化 System.Web.Mvc.WebViewPage<TModel> 类的新实例。        protected WebViewPage();         // 摘要:        //    获取或设置 System.Web.Mvc.AjaxHelper 对象,该对象用于使用 Ajax 呈现 HTML 标记。        //        // 返回结果:        //    用于使用 AJAX 呈现 HTML 标记的System.Web.Mvc.AjaxHelper 对象。        public AjaxHelper<TModel> Ajax { get; set; }        //        // 摘要:        //    获取或设置 System.Web.Mvc.HtmlHelper 对象,该对象用于呈现 HTML 元素。        //        // 返回结果:        //    用于呈现 HTML 元素的 System.Web.Mvc.HtmlHelper 对象。        public HtmlHelper<TModel> Html {get; set; }        //        // 摘要:        //    获取关联的 System.Web.Mvc.ViewDataDictionary 对象的 Model属性。        //        // 返回结果:        //    关联的 System.Web.Mvc.ViewDataDictionary 对象的 Model属性。        public TModel Model { get; }        //        // 摘要:        //    获取或设置一个字典,其中包含在控制器和视图之间传递的数据。        //        // 返回结果:        //    一个字典,其中包含在控制器和视图之间传递的数据。        public ViewDataDictionary<TModel>ViewData { get; set; }         // 摘要:        //    初始化 System.Web.Mvc.AjaxHelper、System.Web.Mvc.HtmlHelper和 System.Web.Mvc.UrlHelper        //    类。        public override void InitHelpers();        //        // 摘要:        //    设置视图数据。        //        // 参数:        //  viewData:        //    视图数据。        protected override void SetViewData(ViewDataDictionaryviewData);    }}


代码段 1

        好了,现在我们进入泛型类HtmlHelper<TModel>的定义(代码段2),在这里可以看到两个大家肯定会感兴趣的属性,即ViewData和ViewBag。没错,这就是我们用于保持不同Http请求之间状态的那两个东东。

    public class HtmlHelper<TModel> :HtmlHelper    {        private DynamicViewDataDictionary_dynamicViewDataDictionary;        privateViewDataDictionary<TModel> _viewData;         public HtmlHelper(ViewContextviewContext, IViewDataContainer viewDataContainer)            : this(viewContext,viewDataContainer, RouteTable.Routes)        {        }         public HtmlHelper(ViewContextviewContext, IViewDataContainer viewDataContainer, RouteCollectionrouteCollection)            : base(viewContext,viewDataContainer, routeCollection)        {            _viewData = new ViewDataDictionary<TModel>(viewDataContainer.ViewData);        }         public new dynamic ViewBag        {            get            {                if (_dynamicViewDataDictionary== null)                {                    _dynamicViewDataDictionary= new DynamicViewDataDictionary(() => ViewData);                }                 return_dynamicViewDataDictionary;            }        }         public newViewDataDictionary<TModel> ViewData        {            get { return _viewData; }        }    }


代码段 2

        大家看ViewData和ViewBag属性的定义中用了new关键字,这是为什么?我们知道,关键字new除了常用来创建对象,还有一个作用是覆写父类的同名成员。由此可知,在泛型类HtmlHelper<TModel>的父类中,肯定也存在一个叫ViewData的成员。(注:本篇文章第二自然段中的语句【public newHtmlHelper<TModel> Html { get; set; }】也是这个意思。)我们进入泛型类HtmlHelper<TModel>的父类HtmlHelper,果然不出所料,确实有ViewData属性和ViewBag属性,见代码段3,其中ViewData是一个字典,ViewBag是一个动态类型(dynamic)。怎么样?这就是ViewData和ViewBag的庐山真面目。

  

      public ViewDataDictionary ViewData        {            get { returnViewDataContainer.ViewData; }        }        public dynamic ViewBag        {            get            {                if (_dynamicViewDataDictionary== null)                {                    _dynamicViewDataDictionary= new DynamicViewDataDictionary(() => ViewData);                }                return _dynamicViewDataDictionary;            }        }

代码段 3

        我们在HtmlHelper类中并没有找到常用的ActionLink、TextBox等Helper,回想一下上篇文章中关于ActionLink的分析,可以知道MVC框架内置的HtmlHelper是以扩展方法的形式进行定义的,这些扩展方法存在于MVC源码中的“System.Web.MVC/Html”路径下,名称包含Extention的类中,例如InputExtensions、LabelExtensions、ChildActionExtensions、FormExtensions、NameExtensions、PartialExtensions、SelectExtensions、TextAreaExtensions等等。

        下面我们着重说一下FormExtensions类。在这个类中,我们可以找到常用的@Html.BeginForm的定义,没错,这就是Razor中用来定义Web表单的Helper。用过这个Helper的人都会注意到一个细节,就是BeginForm的用法是【@using (Html.BeginForm()){}】,和普通的Helper不同。这种用法可以让我们不用调用EndForm方法,但这是为什么呢?

        见到using关键字,我们都知道在这里它的作用是在代码块结束之前,自动调用Dispose方法,当然,using代码块中的对象必须实现了IDisposable接口。找到BeginForm的定义(代码段4),发现这个方法的返回值是一个MvcForm对象。

        public static MvcForm BeginForm(thisHtmlHelper htmlHelper)        {            // generates <formaction="{current url}" method="post">...</form>            string formAction =htmlHelper.ViewContext.HttpContext.Request.RawUrl;            return FormHelper(htmlHelper, formAction,FormMethod.Post, new RouteValueDictionary());        }


代码段 4

        跟踪进入MvcForm类的定义,可以看到这个类果然实现了IDisposable接口,狂喜!在MvcForm类的定义中,找到Dispose方法的实现(代码段5),豁然开朗吧?原来在Dispose方法中调用了FormExtensions.EndForm方法。

        public void Dispose()        {            Dispose(true /* disposing */);            GC.SuppressFinalize(this);        }         protected virtual void Dispose(booldisposing)        {            if (!_disposed)            {                _disposed = true;                FormExtensions.EndForm(_viewContext);            }        }


代码段 5

        继续进入FormExtensions.EndForm方法的定义(代码段6),更加豁然开朗吧?继续狂喜!EndForm方法的作用正是向浏览器发送Web表单的结束标记</form>。

        internal static voidEndForm(ViewContext viewContext)        {           viewContext.Writer.Write("</form>");           viewContext.OutputClientValidation();            viewContext.FormContext = null;        }


代码段 6

0 0
原创粉丝点击