從開發者的角度來看,建立Asp.net MVC的View是一件很爽的事,因為你可以精确控制最終生成的HTML。具有諷刺意味的是不得不寫出每一行HTML代碼同時也是Asp.net MVC的View中讓人不爽的地方。讓我用我的一個經曆來告訴我建立ASP.Net MVC view Helpers背後靈感的由來。由一小部分開發人員(包括我)和一個CSS設計人員(我們叫他Ricky)組成的小組,開始了一個新的Asp.net MVC的項目,在項目開發過程中;我給頁面添加了一些TextBox和一些其他元素,我check-in了我的代碼,直到回家我也沒再想起過這事。隔夜早晨,剛上班時我就從CSS設計那裡收到一封郵件來通知我我必須按照他的CSS指導方針來寫HTML,比如說對于textbox,必須遵循以下規則:
每個textbox必須内嵌在li标簽中
每一個textbox都必須有一個label标簽的for屬性與之對應
textbox必須使用input标簽并設定type屬性為text
對于這些要求我一一照做并修改我的代碼符合了後兩條規則,但我忘了關于li的指導方針,我很快更新了頁面并送出了我的代碼。幾天後,項目又推進了很多,Ricky來到我的辦公桌前并讓我看看我所做的改變。打開頁面,他開始一一列舉那些我不遵循它的UI規定的地方,有很多地方我都忽視了因為我甚至不知道這些指導方針的存在.在他指出這些後,我想:一定會有方法可以讓我們兩個人都如願以償.對于我來說隻是需要html标簽的id,對于Ricky來說他需要我的HTML符合規範來讓他的CSS檔案能夠選擇到合适的html。是以我們引入了view helper.
在我用Asp.net MVC時我注意到我自己寫了很多純Html,比如div和span,同時伴随使用了很多System.Web.Mvc.HtmlHelper來生成html,比如說一個輸入名字的textbox:
<li>
<label for="FirstName">First name</label>
<%= Html.TextBox("FirstName") %>
<%= Html.ValidationMessage("FirstName", "*") %>
</li>
我就想,是不是能有一種方法來将上面的所有代碼融合在一起呢。這樣不僅讓我程式設計更加輕松,而且再也不用擔心Ricky給我設定的條條框框了。理想的情況下會滿足以下标準:
容易執行
重用性好
強制執行某些标準(比如Ricky的)
和标準的HtmlHelper擴充方法用起來沒太大差別
容易使用
在我們進入執行這個的細節之前如果你感覺這聽起來像又回到了Web Form時代,那就錯了。view helper僅僅是在建立HTML的時候起輔助作用,而不是将HTML進行抽象。我關心的隻是HTML在頁面中的顯示效果以及使用javascript的行為更輕松.而不是textbox是否放入li中,當我需要建立一個textbox時,我隻需在view中放入如下代碼:
<% Html.NewText("FirstName", "First name"); %>
我想聲明我僅僅是想将建立HTML延遲到另一個類中。使用View helper我可以輕松做到這一點。首先我們先來看标準的HtmlHelper擴充方法如何做到這一點.
Html helper有兩種實作用法,大多數的使用方法都會如下:
<%= Html.TextBox("FirstName") %>
而還有一種用法和聲明一個form元素很相似:
<% using (Html.BeginForm()) { %>
<!-- Other elements here-->
<% } %>
上面兩種方法的主要差別是Html.TextBox僅僅傳回一個string來注入到view中。這也是為什麼使用<%=而不是标準的的代碼塊。而另一種以對象作為傳回類型的方法更老練許多,比如,System.Web.Mvc.Html.MvcForm,這個對象放入using語句.對象被建立時一些HTML就會被注入到view中(嚴格說:并不是對象建立時,但很接近)還有一些事在對象被回收時将html注入view(也就是碰到”}”符号時).使用這種方法的好處是可以在using語句之間插入代碼。這使它的能力無疑比那些僅僅傳回一個字元串注入頁面的方式要強大許多。
是以,我選擇第二種方法來實作我的View Helpers.是以HtmlHelper擴充方法會實作我建立的IViewObject接口對象。類圖如下:
1
可以看到,IViewObject實作了System.IDisposable接口。這使實作如前面所提到和Html.BeginForm的使用方法類似所必須的。IViewObject有兩個方法,StartView和EndView.這兩個方法分别在對象建立時和對象回收時被調用.為了讓這些對象的建立更加容易我建立了一個抽象類來處理:執行方法,回收對象和在合适的時候調用EndView方法。類圖如下:
2
上圖中的抽象類完整代碼如下:
public abstract class AbstractHtmlViewObject : IViewObject
{
private bool mDisposed;
public AbstractHtmlViewObject(ViewRequestContext requestContext, string name)
{
if (requestContext == null)
{ throw new ArgumentNullException("requestContext"); }
ViewRequestContext = requestContext;
Name = name;
}
public IViewRequestContext RequestContext
get;
protected set;
#region IViewObject Members
public object Attributes { get; set; }
public string Name { get; set; }
public abstract void StartView();
public abstract void EndView();
#endregion
// based on System.Web.Mvc.HtmlHelper.GetModelStateValue
public object GetModelStateValue(string key, Type destinationType)
{
object result = null;
ModelState modelState;
if (ViewRequestContext.HtmlHelper.ViewData.ModelState.TryGetValue(
key, out modelState))
{
result = modelState.Value.ConvertTo(destinationType, null);
}
return result;
}
#region IDisposable Members
public void Dispose()
Dispose(true);
GC.SuppressFinalize(this);
protected virtual void Dispose(bool disposing)
if (!mDisposed)
{
mDisposed = true;
EndView();
}
#endregion
}
如你所見上面AbstractHtmlViewObject對象不僅滿足了最上面提到的清單(Ricky那段裡),還包含了一些輔助類更容易擴充的東西。也就是它包含的一個屬性:RequestContext,這個屬性可以幫助我們很容易建立HTML和擴充方法GetModelStateValue,我們會在後面詳細講述GetModelStateValue的使用方法。我們會在後面講述RequestContext的細節,這裡我們先看看如何建立我們先前讨論的那個textbox。
-------------------------------------------
待續…
原文連結:http://mvcviewhelpers.codeplex.com/
translated by CareySon
分類: Asp.net MVC
本文轉自CareySon部落格園部落格,原文連結:http://www.cnblogs.com/CareySon/archive/2010/01/05/1639825.html,如需轉載請自行聯系原作者