天天看點

譯】使用自定義ViewHelper來簡化Asp.net MVC view的開發------part3

   接上篇…現在讓我們開始讨論如何建立HtmlHelper擴充方法.

   在前面我們說到了建立HtmlText類的方方面面。包括為HtmlText建立的擴充方法.這些擴充方法包括直接被View調用的那些擴充方法。下面代碼展示了HtmlText的幾種不同的構造函數:

public static class HtmlHelperExtensions 

    #region Textbox 

    public static IViewObject NewText( 

        this HtmlHelper htmlHelper, string name) 

    { 

        return NewText(htmlHelper, name, null); 

    } 

        this HtmlHelper htmlHelper, string name, string labelText) 

        return NewText(htmlHelper, name, labelText, null); 

        this HtmlHelper htmlHelper, string name, string labelText, object value) 

        return NewText(htmlHelper, name, labelText, value, null, false, true, null); 

        this HtmlHelper htmlHelper, string name, string labelText, object value,  

        string validationMessage, bool @readonly, bool createLi, object attributes) 

        IViewObject viewObject = new HtmlText( 

            new ViewRequestContext(htmlHelper), name, labelText, value,  

            validationMessage, @readonly, createLi, attributes); 

        viewObject.StartView(); 

        return viewObject; 

    #endregion 

    //NOTE: SOME CONTENT OMITTED FROM THIS SNIPPET 

   NewText方法有四個不同版本的重載,這些重載都屬于System.Web.Mvc.HtmlHelper的擴充方法,隻有最後一個方法用于真正的起作用,而其他的方法都是這個方法的封裝以便讓使用者使用起來更簡單.上面的代碼中HtmlText對象通過傳入适當的參數來初始化,而view是通過StartView方法來初始化,在StartView中被調用的HtmlText會傳回合适的對象動态的将Html注入View.現在讓我們來看看如何在view中使用這些方法。

     前面我們已經建立了在View中可使用的HtmlText對象,現在就可以使用了。在前面我們提到,如果想要建立一個textbox來滿足Ricky的标準,我必須寫如下代碼:

<li> 

    <label for="FirstName">First name</label> 

    <%= Html.TextBox("FirstName") %> 

    <%= Html.ValidationMessage("FirstName", "*") %> 

</li> 

    現在通過使用HtmlHelper,我們可以把代碼簡化如下:

<% Html.NewText("FirstName", "First name"); %> 

    上面兩種方法所生成的Html是完全相同的,我們實作了前面設定的目标。從今往後就可以使用這個Helper來簡化Asp.net MVC view的開發了。上面代碼中并沒有用到EndView方法.下面我們來研究一個更複雜一些的HTML的構造—radio button,看是如何實作的

     使用Asp.net MVC來建立一組radio button,代碼一般如下:

    <div class="option-group" id="GenderContainer"> 

        <label for="Gender">Gender</label> 

        <% foreach (SelectListItem item in Model.GenderList) 

           { %> 

                <%= Html.RadioButton(item.Text, item.Value)%> 

                <span><%= item.Text%></span> 

        <% } %> 

    </div> 

    上面代碼是從AddContactClass.aspx view中節選的,所有代碼可以從這篇文章的網站下載下傳,上面代碼中ContactController通過Model.GenderList屬性來集中傳回代碼:

public ActionResult AddContactClassic() 

    AddContactModel addModel = InternalGetInitialAddModel(); 

    return View(addModel); 

private AddContactModel InternalGetInitialAddModel() 

    string maleString = Gender.Male.ToString(); 

    string femaleString = Gender.Female.ToString(); 

     IList<SelectListItem> genderRadioButtons = new List<SelectListItem>() 

        new SelectListItem { Text = maleString, Value = maleString }, 

        new SelectListItem { Text = femaleString, Value = femaleString } 

    }; 

    AddContactModel model = new AddContactModel { GenderList = genderRadioButtons }; 

    return model; 

生成的HTML效果圖如下:

1

在上面建立radio button的代碼中有很多掩蓋了元素真實意圖(譯者按:比如說為什麼我們這麼寫HTML,是為了滿足Ricky的标準嗎?)的部分,比如說:外層的div和内層的span是為了label而包裹文本.而如果我們需要一組radio button時隻需要聲明一下并指定相關的值那不是更爽嗎?下面我們建立HtmlRadioButtonGroup view helper,它可以滿足我們隻聲明并指定相關值就能建立出相應的html,使用HtmlRadioButtonGroup,我們可以将前面的radio button精簡如下:

<% Html.NewRadioButtonGroup("Gender", Model.GenderList); %> 

上面代碼中,我們可以從更高的視角來建立Html,清楚的這段代碼的作用而不是關注Html的細節。下面來建立一個替我們生成HTML的helper,也就是為:HtmlRadioButtonGroup類,下面代碼展示了這個類唯一的構造函數和它的字段:

private readonly List<SelectListItem> mSelectList; 

private readonly bool mCreateLi; 

public HtmlRadioButtonGroup( 

    ViewRequestContext requestContext, string name,  

    IEnumerable<SelectListItem> selectList, bool createLi, object attributes) 

    : base(requestContext, name) 

    mSelectList = new List<SelectListItem>(); 

    if (selectList != null) 

        mSelectList.AddRange(selectList); 

    mCreateLi = createLi; 

    Attributes = attributes; 

}

看上去是不是和我們先前的HtmlText對象的構造器很像?它的構造函數為通過傳參的方式将RequestContext變得可用。并且通過構造函數為所有的字段進行初始化,這也意味着這個類是在StartView方法中(譯者按:因為RequestContext方法在StartView中可以傳入)的,下面代碼是StartView的完全版本:

public override void StartView() 

    HttpResponseBase httpResponse = RequestContext.HttpResponse; 

    TagBuilder liTagBuilder = new TagBuilder("li"); 

    if (mCreateLi) 

        httpResponse.Write(liTagBuilder.ToString(TagRenderMode.StartTag)); 

    TagBuilder divTag = new TagBuilder("div"); 

    divTag.AddCssClass("option-group"); 

    divTag.MergeAttribute("name", Name); 

    if (Attributes != null) 

        divTag.MergeAttributes(new RouteValueDictionary(Attributes)); 

    TagBuilder labelTag = new TagBuilder("label"); 

    labelTag.MergeAttribute("for", Name); 

    labelTag.SetInnerText(Name); 

    httpResponse.Write(labelTag.ToString(TagRenderMode.Normal)); 

    httpResponse.Write(divTag.ToString(TagRenderMode.StartTag)); 

    // Write out the radio buttons, let the MVC Helper do the hard work here 

    foreach (SelectListItem item in this.mSelectList) 

        string text = !string.IsNullOrEmpty(item.Text) 

                        ? item.Text 

                        : item.Value; 

        httpResponse.Write(RequestContext.HtmlHelper.RadioButton( 

            Name, item.Value, item.Selected)); 

        // Note: Because we are using HtmlHelper.RadioButton the <input>  

        //       elements will have duplicate ids 

        //       See: http://forums.asp.net/t/1363177.aspx 

        //       In order to avoid this we could do this ourselves here 

        TagBuilder spanTag = new TagBuilder("span"); 

        spanTag.SetInnerText(text);        

         httpResponse.Write(spanTag.ToString(TagRenderMode.Normal)); 

    httpResponse.Write(divTag.ToString(TagRenderMode.EndTag)); 

    if (this.mCreateLi) 

        httpResponse.Write(liTagBuilder.ToString(TagRenderMode.EndTag)); 

這裡的想法和HtmlText類如初一撤,那就是:所有的HTML代碼都在StartView方法中生成。是以這裡StartView方法建立了一些HTML tag,并周遊mSelectList中的元素并通過Asp.net MVC自帶的RadioButton擴充方法為每一個元素生成一個RadioButton。在重用這些方法時最好先重寫這些方法(譯者按:看上面代碼注釋)。

從上面代碼中的注釋可以看出,使用HtmlHelper.RadioButton擴充方法有一個明顯的bug,就是id和name用的是同一個值,這裡因為name屬性本來就應該為RadioButton設定成相同的這樣他們便可以邏輯上連成一組,但是id屬性是每個元素唯一擁有,這裡解決這個bug的方法是不用這個方法,但在這裡為了簡單起見我們先使用這個方法.上面建立的兩個Html helper對象都沒有用到EndView方法,你可以已經開懷疑這個方法為什麼存在,在接下來的HtmlFieldSet的Helper我會給你展示EndView的用途

-------------------------------------------

待續…

原文連結:http://mvcviewhelpers.codeplex.com/

translated by CareySon

分類: Asp.net MVC

本文轉自CareySon部落格園部落格,原文連結http://www.cnblogs.com/CareySon/archive/2010/01/06/1640057.html如需轉載請自行聯系原作者

繼續閱讀