C#進階系列——一步一步封裝本身的HtmlHelper組件:BootstrapHelper

前言:以前學習過不少的Bootstrap組件,博主就在腦海裏構思:是否能夠封裝一套本身Bootstrap組件庫呢。再加上看到MVC的Razor語法裏面直接經過後臺方法輸出前端控件的方式,因而打算仿照HtmlHelper封裝一套BootstrapHelper,今天只是一個開頭,講述下如何封裝本身的Html組件,之後慢慢完善。css

本文原創地址:http://www.cnblogs.com/landeanfen/p/5729551.htmlhtml

BootstrapHelper系列文章目錄前端

1、揭開HtmlHelper的「面紗」

常用Razor寫法的園友都知道,在cshtml裏面,咱們能夠經過後臺的方法輸出成前端的html組件,好比咱們隨便看兩個例子:git

輸出成Html以後web

博主的好奇心又來了,它是怎麼作到的呢?因而將 Html 對象以及 Label() 方法轉到定義ide

由此能夠看出Html對象是HtmlHelper類型的一個實例,而Label()方法則是HtmlHelper類型的一個擴展方法,因此就能夠直接經過Html.Label()這種方式直接調用。不熟悉C#擴展方法的園友能夠看看http://www.cnblogs.com/landeanfen/p/4632467.html函數

 既然咱們想要封裝本身的HtmlHelper,那麼咱們就必需要了解Label()方法裏面是如何實現的,咱們偉大的Reflector又派上用場了。咱們來反編譯System.Web.MVC.dll看看。找到LabelExtensions這個類post

通過一系列的轉到定義,咱們找到最終的方法學習

一樣,咱們找到TextBox()最終定義的方法ui

喲西,原來就是TagBuilder這個一個小東西,讓人以爲神奇得不要不要的。因此有時咱們須要勇於反編譯,或許看似高級的背後其實很簡單呢~~

2、BootstrapHelper組件封裝準備

一、定義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)
        { }
    }
}

這樣經過子類複用父類的構造函數的方式便可解決以上問題。編譯經過!

二、定義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標籤訂義了本身的樣式,那麼這裏改爲你須要的樣式便可。以上代碼都比較基礎,這裏就不一一講解。

三、定義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();
        }
    }
}

至於這裏的泛型,咱們之後再來作講解,這裏先不作過多糾結

 四、實踐

 有了以上三步,全部須要的方法和變量都齊全了,貌似已經「萬事俱備只欠東風」了,是否是這樣呢?咱們來試一把

編譯,將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>

再次運行

3、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());
        }
    }
}

呵呵,是否是有模有樣~~可能又有人要說博主「山寨」了,呵呵,無論山寨不山寨,你以爲爽就行。

4、總結

 這篇先到這裏,一路填坑,基本功能總算可用。還有一些須要完善的地方,好比泛型,好比lamada表達式等等,來日方長,博主有時間完善下。還有最基礎的一些表單控件,咱們都須要封裝,這個估計還有點工做量,只能慢慢來完善了,等完善都必定的程度會開源在git上,但願本身可以堅持下去!若是你以爲本文對你有幫助,請幫忙推薦下,您的推薦是博主堅持完善的動力。

本文原創出處:http://www.cnblogs.com/landeanfen/

歡迎各位轉載,可是未經做者本人贊成,轉載文章以後必須在文章頁面明顯位置給出做者和原文鏈接,不然保留追究法律責任的權利

相關文章
相關標籤/搜索