接上篇,我們下面通過HtmlFiledSet helper來展示何時使用EndVIEw():
如果你用ASP.net已經有一段時間了,那使用Html.BeginForm helper來創建Html form標簽的方式會讓你覺得有點怪.當你創建一個新的ASP.Net mvc項目後,在VIEw裡的ChangePassWord.ASPx會默認被創建,這個頁面使用了Html.BeginForm helper,下面是使用這個helper的代碼段:
<% using (Html.BeginForm()) { %>
<div>
<fIEldset>
<legend>Account Information</legend>
<p>
<label for="currentPassword">Current passWord:</label>
<%= Html.Password("currentPassWord") %>
<%= Html.ValidationMessage("currentPassWord") %>
</p>
<p>
<label for="newPassword">New passWord:</label>
<%= Html.Password("newPassWord") %>
<%= Html.ValidationMessage("newPassWord") %>
</p>
<p> <label for="confirmPassword">Confirm new passWord:</label>
<%= Html.Password("confirmPassWord") %>
<%= Html.ValidationMessage("confirmPassWord") %>
</p>
<p>
<input type="submit" value="Change PassWord" />
</p>
</fIEldset>
</div>
<% } %>
上面代碼中你會發現Html.BeginForm的使用和<%=Html.Password(“currentPassWord”) %>的使用不盡相同,也就是Html.BeginForm在using語句中被調用,這點很有意思,讓我先來看看上面代碼段生成後的Html,如下:
<form
action="/Account/LogOn?ReturnUrl=%2fAccount%2fChangePassWord"
method="post">
<div>
<fIEldset>
<legend>Account Information</legend>
<p>
<label for="username">Username:</label>
<input id="username" name="username" type="text" value="" />
</p>
<p>
<label for="password">PassWord:</label>
<input id="password" name="password" type="passWord" />
</p>
<p>
<input id="rememberMe" name="rememberMe" type="checkbox" value="true" />
<input name="rememberMe" type="hidden" value="false" />
<label class="inline" for="rememberMe">Remember me?</label>
</p>
<p>
<input type="submit" value="Log On" />
</p>
</fIEldset>
</div>
</form> 比較<%= Html.Password("currentPassword") %> 語句和Html.BeginForm所生成的HTML代碼你會發現password那段僅僅僅僅將調用passWord擴展方法變成對應的Html,而BeginForm調用HTML擴展方法來注入form的開始標簽,<form…>,和using語句結束時(“}”)注入標簽<./form>.這種方式十分方便,因為我們可以一方面使用vIEw helper創建合適的form標簽,另一方面在form標簽內插入任何我們想插入的html.這種方法的工作原理是當你調用Html.BeginForm方法並返回MvcForm類型的對象,這個對象在using語句中所以當對象被回收(譯者按:也就是Dispose)的時候,也就是執行到結尾的”<% } %>”時,關閉標簽</form>將會被寫入到VIEw中.下面是Dispose方法的實現:
public void Dispose() {
Dispose(true /* disposing */);
GC.SupPRessFinalize(this);
}
protected virtual void Dispose(bool disposing) {
if (!_disposed) {
_disposed = true;
_httpResponse.Write("</form>");
}
}
我們用相似的方法來實現HtmlFIEldSet:
從這篇文章附帶的代碼中有一個”DetailsClassic.ASPx”頁面中,一些字段包含於fIEldset元素中,具體代碼如下:
<fieldset class="details-fIEld-group" name="Details">
<legend>Details</legend>
<ol>
<li>
<label for="FirstName">FirstName</label>
<span id="FirstName">
<%= Html.Encode(Model.FirstName) %></span>
</li>
<li>
<label for="LastName">LastName</label>
<span id="LastName"><%= Html.Encode(Model.LastName) %></span>
</li>
<li>
<label for="Email">Email</label>
<span id="Email"><%= Html.Encode(Model.Email) %></span>
</li>
<li>
<label for="Phone">Phone</label>
<span id="Phone"><%= Html.Encode(Model.Phone) %></span>
</li>
<li>
<label for="Gender">Gender</label>
<span id="Gender"><%= Html.Encode(Model.Gender) %></span>
</li>
</ol>
</fieldset> 如果能用一個vIEw helper來創建下面所有的Html標簽,那會惬意很多:
fIEldset的開始標記
legend標簽
ol的開始標簽
ol的結束標簽
fIEldset的結束標簽
如果能用view helper來處理這些,那上面那段代碼無疑會簡單很多,尤其再加上使用Html.Text標簽來代替上面的text域。讓我們開始做到這一點,首先創建一個實現IViewObject接口的類,命名為HtmlFIEldSet類並繼承與AbstractHtmlVIEwObject,整個類的代碼附下:
public class HtmlFIEldset : AbstractHtmlVIEwObject
{
private readonly string mTitle;
public HtmlFIEldset(
VIEwRequestContext requestContext, string name,
string title, object attributes)
: base(requestContext, name)
{
mTitle = title;
Attributes = attributes;
}
private TagBuilder FIEldsetTag { get; set; }
private TagBuilder OlTag { get; set; }
public override void StartVIEw()
{
HttpResponseBase httpResponse = RequestContext.HttpResponse;
FieldsetTag = new TagBuilder("fIEldset");
// apply any Attributes passed in
if (Attributes != null)
{
FIEldsetTag.MergeAttributes(new RouteValueDictionary(Attributes));
}
// The Name property should override any passed into the Attributes
FIEldsetTag.MergeAttribute("name", Name, true);
httpResponse.Write(FIEldsetTag.ToString(TagRenderMode.StartTag));
if (!string.IsNullOrEmpty(mTitle))
{
TagBuilder legendTag = new TagBuilder("legend");
legendTag.SetInnerText(mTitle);
httpResponse.Write(legendTag.ToString(TagRenderMode.Normal));
}
OlTag = new TagBuilder("ol");
httpResponse.Write(OlTag.ToString(TagRenderMode.StartTag));
}
public override void EndVIEw()
{
HttpResponseBase httpResponse = RequestContext.HttpResponse;
httpResponse.Write(OlTag.ToString(TagRenderMode.EndTag));
httpResponse.Write(FIEldsetTag.ToString(TagRenderMode.EndTag));
}
}
這個類的實現和其它的view對象沒什麼不同,除了EndView方法,在這裡我們需要EndView方法來生成必須的結束標記。當然我們也可以使用EndVIEw來生成任何需要的Html,在這裡我們僅是用它生成結束標記。
-------------------------------------------
待續…