C#进阶系列——一步一步封装自己的HtmlHelper组件:BootstrapHelper-阿里云开发者社区

开发者社区> 嗯哼9925> 正文

C#进阶系列——一步一步封装自己的HtmlHelper组件:BootstrapHelper

简介:
+关注继续查看

 

正文

前言:之前学习过很多的Bootstrap组件,博主就在脑海里构思:是否可以封装一套自己Bootstrap组件库呢。再加上看到MVC的Razor语法里面直接通过后台方法输出前端控件的方式,于是打算仿照HtmlHelper封装一套BootstrapHelper,今天只是一个开头,讲述下如何封装自己的Html组件,以后慢慢完善。

本文原创地址:http://www.cnblogs.com/landeanfen/p/5729551.html

BootstrapHelper系列文章目录

一、揭开HtmlHelper的“面纱”

经常使用Razor写法的园友都知道,在cshtml里面,我们可以通过后台的方法输出成前端的html组件,比如我们随便看两个例子:

输出成Html之后

博主的好奇心又来了,它是怎么做到的呢?于是将 Html 对象以及 Label() 方法转到定义

由此可以看出Html对象是HtmlHelper类型的一个实例,而Label()方法则是HtmlHelper类型的一个扩展方法,所以就可以直接通过Html.Label()这种方式直接调用。不熟悉C#扩展方法的园友可以看看http://www.cnblogs.com/landeanfen/p/4632467.html

 既然我们想要封装自己的HtmlHelper,那么我们就必须要了解Label()方法里面是如何实现的,我们伟大的Reflector又派上用场了。我们来反编译System.Web.MVC.dll看看。找到LabelExtensions这个类

经过一系列的转到定义,我们找到最终的方法

同样,我们找到TextBox()最终定义的方法

哟西,原来就是TagBuilder这个一个小东西,让人觉得神奇得不要不要的。所以有时我们需要敢于反编译,或许看似高级的背后其实很简单呢~~

二、BootstrapHelper组件封装准备

1、定义BootstrapHelper

有了以上的基础做准备,接下来就是具体的实现了,我们新建了一个空的MVC项目,添加如下文件。

编译发现报错如下

将HtmlHelper转到定义发现它有两个构造函数,分别有两个、三个参数

 那么,我们的BootstrapHelper也定义两个构造函数,于是代码变成这样:

复制代码
namespace Extensions
{
    public class BootstrapHelper : System.Web.Mvc.HtmlHelper
    {
        /// <summary>
        /// 使用指定的视图上下文和视图数据容器来初始化 BootstrapHelper 类的新实例。
        /// </summary>
        /// <param name="viewContext">视图上下文</param>
        /// <param name="viewDataContainer">视图数据容器</param>
        public BootstrapHelper(ViewContext viewContext, IViewDataContainer viewDataContainer)
            : base(viewContext, viewDataContainer)
        { }

        /// <summary>
        /// 使用指定的视图上下文、视图数据容器和路由集合来初始化 BootstrapHelper 类的新实例。
        /// </summary>
        /// <param name="viewContext">视图上下文</param>
        /// <param name="viewDataContainer">视图数据容器</param>
        /// <param name="routeCollection">路由集合</param>
        public BootstrapHelper(ViewContext viewContext, IViewDataContainer viewDataContainer, RouteCollection routeCollection)
            : base(viewContext, viewDataContainer, routeCollection)
        { }
    }
}
复制代码

这样通过子类复用父类的构造函数的方式即可解决以上问题。编译通过!

2、定义LabelExtensions

上面我们研究过HtmlHelper,在HtmlHelper里面,不同的html组件定义了不同的Extension(扩展),下面我们就以最简单的Label标签为例定义我们BootstrapHelper里面的Label标签。

同样,在Extensions文件夹里面我们新建了一个文件LabelExtensions.cs,用于定义Label标签的扩展,它里面的基本实现如下:

复制代码
namespace Extensions
{
    public static class LabelExtensions
    {
        /// <summary>
        /// 通过使用指定的 HTML 帮助器和窗体字段的名称,返回Label标签
        /// </summary>
        /// <param name="html">扩展方法实例</param>
        /// <param name="id">标签的id</param>
        /// <param name="content">标签的内容</param>
        /// <param name="cssClass">标签的class样式</param>
        /// <param name="htmlAttributes">标签的额外属性(如果属性里面含有“-”,请用“_”代替)</param>
        /// <returns>label标签的html字符串</returns>
        public static MvcHtmlString Label(this BootstrapHelper html, string id, string content, string cssClass, object htmlAttributes)
        {
            //定义标签的名称
            TagBuilder tag = new TagBuilder("label");
            //给标签增加额外的属性
            IDictionary<string, object> attributes = BootstrapHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
            if (!string.IsNullOrEmpty(id))
            {
                attributes.Add("id", id);
            }
            if (!string.IsNullOrEmpty(cssClass))
            {
                //给标签增加样式
                tag.AddCssClass(cssClass);
            }
            //给标签增加文本
            tag.SetInnerText(content);
            tag.AddCssClass("control-label");
            tag.MergeAttributes(attributes);
            return MvcHtmlString.Create(tag.ToString());
        }
    }
}
复制代码

我们暂且只定义一个方法,其他的重载我们很好扩展,这里给所有的BootstrapHelper里面的Label标签统一添加了“control-label”样式,当然,如果你的项目里面的label标签定义了自己的样式,那么这里改成你需要的样式即可。以上代码都比较基础,这里就不一一讲解。

3、定义BootstrapWebViewPage

以上定义了BootstrapHelper和LabelExtensions,准备工作是做好了,但是还少一个对象,比如我们在cshtml页面里面 @Html.Label("姓名") 这样写,Html变量是一个HtmlHelper类型的对象,那么,如果我们需要使用类似 @Bootstrap.Label() 这种写法,以此类推,Bootstrap变量应该也是一个BootstrapHelper类型的对象,那么如果我们要这么用,必须要先定义一个Bootstrap变量,这个变量到底在哪里定义呢。于是博主思考,Html变量是定义在哪里的呢?再次转到定义

原来是在WebViewPage这个类的子类中,同样,我们在Extensions文件夹里面也新建一个WebViewPage的子类BootstrapWebViewPage,实现代码如下:

复制代码
namespace Extensions
{
    public abstract class BootstrapWebViewPage<T> : System.Web.Mvc.WebViewPage<T>
    {
        //在cshtml页面里面使用的变量
        public BootstrapHelper Bootstrap { get; set; }

        /// <summary>
        /// 初始化Bootstrap对象
        /// </summary>
        public override void InitHelpers()
        {
            base.InitHelpers();
            Bootstrap = new BootstrapHelper(ViewContext, this);
        }

        public override void Execute()
        {
            //throw new NotImplementedException();
        }
    }
}
复制代码

至于这里的泛型,我们以后再来做讲解,这里先不做过多纠结

 4、实践

 有了以上三步,所有需要的方法和变量都齐全了,貌似已经“万事俱备只欠东风”了,是不是这样呢?我们来试一把

编译,将Index.cshtml页面关闭重新打开,发现仍然找不到Bootstrap对象

怎么回事呢,Html是可以找到的,那Bootstrap变量去哪里了呢。。。

经过一番查找资料,发现在View文件夹里面有一个web.config文件(之前一直没怎么在意这个东西,现在想想里面还是有学问的哦),里面有一个节点system.web.webPages.razor下面有一个pages节点,默认是这样的:

复制代码
  <system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="System.Web.Mvc.WebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
        <add namespace="BootstrapHelper" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>
复制代码

我们将pages节点的pageBaseType改成我们的WebViewPage

复制代码
  <system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="Extensions.BootstrapWebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
        <add namespace="BootstrapHelper" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>
复制代码

然后编译,重新打开Index.cshtml。

OK,可以找到Bootstrap对象了。我们将Index.cshtml里面写入如下内容:

复制代码
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <div> 
        @Html.Label("姓名")
        @Html.TextBox("a", "Jim")
        
        @Bootstrap.Label(null, "Bootstrap Label标签", null, null)
    </div>
</body>
</html>
复制代码

运行看看效果:

 

怎么还是报错呢?这个问题应该不难理解,因为在razor里面使用@调用后台变量和方法的时候也存在命名空间的概念,这个命名空间在哪里引用呢,还是在View文件夹里面的web.config里面,在system.web.webPages.razor节点下面存在namespace的节点,我们将自定义的Label()扩展方法所在的命名空间加进去即可。于是配置变成这样:

复制代码
  <system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="Extensions.BootstrapWebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
        <add namespace="BootstrapHelper" />
        <add namespace="Extensions"/>
      </namespaces>
    </pages>
  </system.web.webPages.razor>
复制代码

再次运行

三、BootstrapHelper组件完善

通过上面一系列发现坑、填坑的经历,一个最最简单的BootstrapHelper组件已经基本可用。我们将LabelExtensions简单完善下:

复制代码
namespace Extensions
{
    public static class LabelExtensions
    {
        public static MvcHtmlString Label(this BootstrapHelper html, string id)
        {
            return Label(html, id, null, null, null);
        }public static MvcHtmlString Label(this BootstrapHelper html, string id, string content)
        {
            return Label(html, id, content, null, null);
        }

        public static MvcHtmlString Label(this BootstrapHelper html, string id, string content, object htmlAttributes)
        {
            return Label(html, id, content, null, htmlAttributes);
        }

        /// <summary>
        /// 通过使用指定的 HTML 帮助器和窗体字段的名称,返回Label标签
        /// </summary>
        /// <param name="html">扩展方法实例</param>
        /// <param name="id">标签的id</param>
        /// <param name="content">标签的内容</param>
        /// <param name="cssClass">标签的class样式</param>
        /// <param name="htmlAttributes">标签的额外属性(如果属性里面含有“-”,请用“_”代替)</param>
        /// <returns>label标签的html字符串</returns>
        public static MvcHtmlString Label(this BootstrapHelper html, string id, string content, string cssClass, object htmlAttributes)
        {
            //定义标签的名称
            TagBuilder tag = new TagBuilder("label");
            //给标签增加额外的属性
            IDictionary<string, object> attributes = BootstrapHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
            if (!string.IsNullOrEmpty(id))
            {
                attributes.Add("id", id);
            }
            if (!string.IsNullOrEmpty(cssClass))
            {
                //给标签增加样式
                tag.AddCssClass(cssClass);
            }
            //给标签增加文本
            tag.SetInnerText(content);
            tag.AddCssClass("control-label");
            tag.MergeAttributes(attributes);
            return MvcHtmlString.Create(tag.ToString());
        }
    }
}
复制代码

呵呵,是不是有模有样~~可能又有人要说博主“山寨”了,呵呵,不管山寨不山寨,你觉得爽就行。

四、总结

 这篇先到这里,一路填坑,基本功能总算可用。还有一些需要完善的地方,比如泛型,比如lamada表达式等等,来日方长,博主有时间完善下。还有最基础的一些表单控件,我们都需要封装,这个估计还有点工作量,只能慢慢来完善了,等完善都一定的程度会开源在git上,希望自己能够坚持下去!如果你觉得本文对你有帮助,请帮忙推荐下,您的推荐是博主坚持完善的动力。






本文转自懒得安分博客园博客,原文链接:http://www.cnblogs.com/landeanfen/p/5729551.html,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
一步一步实现ATL开发的ActiveX组件与javascript的交互(一)
1.      打开VS2008,单击起始页中的“New Project…”,选择“ATL”分类下的“ATL Project”项目,项目名称为“ATLtest”。在随后出现的项目向导中,使用默认配置即可。
1254 0
向Web开发人员推荐12款优秀的 Twitter Bootstrap 组件和工具
  Bootstrap 是基于 HTML,CSS 和 JavaScript 的简洁灵活的流行前端框架及交互组件集,由微博的先驱 Twitter 在2011年8月开源的整套前端解决解决方案。Bootstrap 有非常完备和详尽的开发文档,Web 开发人员能够轻松搭建出清爽风格的界面以及实现良好的交互效果。
1064 0
Cookie 进阶
Cookie作为一个客户端技术被广泛的应用着。我今天也来谈一谈我对Cookie的理解。 先来一个小菜(实现“上次登录时间”) 具体的思路如下: 通过request.getCookies()方法找到目标Cookie,然后获取内容 将最新的时间记录存储到Cookie中,并进行更新的操作 下面是详细的代码: package cookie; import java.
742 0
angular定制组件-bootstrap(css框架)
需要的文件 bootstrap.css ui-bootstrap-tpls.js 模态框 angular定制的bootstrap的模态框,可以方便地将视图与控制器绑定。 模块的定义与模块的控制器: //定义模块时引入依赖 angular .module('myApp', [ 'ui.bootstrap' ]); //定义控制器时传入依赖 angu
1662 0
HTML转PDF组件集锦
通过wkhtmltopdf免费组件,完成Html向PDF转换 开源地址github: https://github.com/codaxy/wkhtmltopdf/tree/master/Tests/Codaxy.
833 0
艾伟_转载:[一步一步MVC]第五回:让TagBuilder丰富你的HtmlHelper
本系列文章导航 [一步一步MVC]第一回:使用ActionSelector控制Action的选择 [一步一步MVC]第二回:还是ActionFilter,实现对业务逻辑的统一Authorize处理 [一步一步MVC]第三回:MVC范例大观园 [一步一步MVC]第四回:漫谈ActionLink,有时“...
769 0
+关注
4463
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载