新聞中心
我們力求頁(yè)面層代碼簡(jiǎn)潔并具有較好的可讀性,在ASP.NET MVC的平臺(tái)上,我們以新的起點(diǎn)來(lái)實(shí)現(xiàn)這一目標(biāo).MvcContrib.FluentHtml和Spark ViewEngine給我們做出了榜樣.本文將以MvcContrib.FluentHtml為例探究它的實(shí)現(xiàn)機(jī)制:Fluent Interface.

10余年的彭山網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開(kāi)發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。成都全網(wǎng)營(yíng)銷(xiāo)推廣的優(yōu)勢(shì)是能夠根據(jù)用戶(hù)設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整彭山建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無(wú)論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)從事“彭山網(wǎng)站設(shè)計(jì)”,“彭山網(wǎng)站推廣”以來(lái),每個(gè)客戶(hù)項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。
在MvcContrib.FluentHtml的應(yīng)用中,我們隨處可以見(jiàn)到下面的代碼:
- < %= this.TextBox(x => x.Person.Name).Title("Enter the person's name").Label("Name:") %>
- ……
- < %= this.Select(x => x.Person.Gender).Options(Model.Genders).Size(5).Label("Gender:")
- .Title("Select the person's gender") %>
瀏覽器中生成的代碼為:
- < LABEL id=Person_Name_Label for=Person_Name>Name:< /LABEL>
- < INPUT id=Person_Name title="Enter the person's name" value=Jeremy maxLength=50 name=Person.Name>
- .
- < SELECT id=Person_Gender title="Select the person's gender" size=5 name=Person.Gender>< OPTION selected value=M>Male< /OPTION>< OPTION value=F>Female< /OPTION>< /SELECT>
上面對(duì)動(dòng)態(tài)生成TextBox和Select的代碼很有意思,我們使用普通的方式在頁(yè)面上生成同樣的客戶(hù)端代碼,CS代碼大致是這樣的:
- Label label = new Label();
- label.Text = "Name";
- TextBox textbox= new TextBox();
- textbox.ToolTip ="Enter the person's name";
- textbox.ID = "No.10001";
- textbox.ID = "Person.Name";
而FluentHtml創(chuàng)建頁(yè)面元素的方式讓我們很容易聯(lián)想到StringBuilder的使用:
- StringBuilder stringbuilder = new StringBuilder();
- stringbuilder.Append("Hello").Append(" ").Append("World!");
Fulent Interface 這種實(shí)現(xiàn)編程方式就是"Fluent Interface",這并不是什么新概念,2005年Eric Evans 和Martin Fowler就為這種實(shí)現(xiàn)方式命名.源文檔
我們分解上面的話(huà):
它是面向?qū)ο驛PI的一種實(shí)現(xiàn)方式,目的是增加代碼的可讀性.。既然我們最熟悉的是StringBuilder,我們就從這個(gè)線(xiàn)索追下去:打開(kāi)Reflector,很容易找到StringBuilder的Append方法:
- public StringBuilder Append(string value)
- {
- if (value != null)
- {
- string stringValue = this.m_StringValue;
- IntPtr currentThread = Thread.InternalGetCurrentThread();
- if (this.m_currentThread != currentThread)
- {
- stringstringValue = string.GetStringForStringBuilder(stringValue, stringValue.Capacity);
- }
- int length = stringValue.Length;
- int requiredLength = length + value.Length;
- if (this.NeedsAllocation(stringValue, requiredLength))
- {
- string newString = this.GetNewString(stringValue, requiredLength);
- newString.AppendInPlace(value, length);
- this.ReplaceString(currentThread, newString);
- }
- else
- {
- stringValue.AppendInPlace(value, length);
- this.ReplaceString(currentThread, stringValue);
- }
- }
- return this;
- }
閱讀這段有兩個(gè)特別要注意的點(diǎn):1.方法的返回值是StringBuilder類(lèi)型 2.***一句:return this;為了深刻理解,我們寫(xiě)一個(gè)簡(jiǎn)單的StringBuilder:
- public interface IContentBuilder
- {
- void WriteContent();
- IContentBuilder Append(string partialContent);
- }
- public class TestContentBuilder : IContentBuilder
- {
- string temp;
- #region IContentBuilder Members
- void IContentBuilder.WriteContent()
- {
- Console.Write(temp);
- }
- IContentBuilder IContentBuilder.Append(string partialContent)
- {
- temp += partialContent;
- return this;
- }
- #endregion
- }
- … …
- //調(diào)用代碼
- IContentBuilder t = new TestContentBuilder();
- t.Append("test").Append("Hello").WriteContent();
跑一下代碼,和StringBuilder效果是一樣的.從上面的應(yīng)用也可以看出:Fluent Interface經(jīng)常用來(lái)完成對(duì)象的構(gòu)造和屬性賦值.
言歸正傳:FluentHTML了解了Fluent Interface,我們來(lái)看一下MVCContrib.FluentHTML的實(shí)現(xiàn),這里以TextBox為例進(jìn)行考察,首先看一下它的繼承關(guān)系:
- public class TextBox : TextInput
- public abstract class TextInput : Input, ISupportsMaxLength where T : TextInput
- public abstract class Input : FormElement where T : Input, Ielement
泛型是一種高層次的算法抽象,我們就通過(guò)Input 一窺端倪:
- public abstract class Input : FormElement where T : Input, IElement
- {
- protected object elementValue;
- protected Input(string type, string name) : base(HtmlTag.Input, name)
- {
- builder.MergeAttribute(HtmlAttribute.Type, type, true);
- }
- protected Input(string type, string name, MemberExpression forMember, IEnumerable behaviors)
- : base(HtmlTag.Input, name, forMember, behaviors)
- {
- builder.MergeAttribute(HtmlAttribute.Type, type, true);
- }
- ///
- /// Set the 'value' attribute.
- ///
- /// The value for the attribute.
- public virtual T Value(object value)
- {
- elementValue = value;
- return (T)this;
- }
- ///
- /// Set the 'size' attribute.
- ///
- /// The value for the attribute.
- public virtual T Size(int value)
- {
- Attr(HtmlAttribute.Size, value);
- return (T)this;
- }
- protected override void PreRender()
- {
- Attr(HtmlAttribute.Value, elementValue);
- base.PreRender();
- }
- }
- 以Size方法為例,可以看出這是一種典型的Fluent Interface實(shí)現(xiàn):
- public virtual T Size(int value)
- {
- Attr(HtmlAttribute.Size, value);
- return (T)this;
- }
分析到這里,上面的語(yǔ)句中還有一點(diǎn)比較奇怪,就是Lambda表達(dá)式的部分:
- this.TextBox(x => x.Person.Name).Title("Enter the person's name").Label("Name:")
TextBox的實(shí)現(xiàn)代碼里面我們沒(méi)有看到對(duì)Lambda表達(dá)式的支持.那是在什么地方完成的呢?通過(guò)跟進(jìn),我們來(lái)到了ViewDataContainerExtensions,它是IViewDataCon
- namespace MvcContrib.FluentHtml
- {
- ///
- /// Extensions to IViewDataContainer
- ///
- public static class ViewDataContainerExtensions
- {
- ///
- /// Generate an HTML input element of type 'text' and set its value from ViewData based on the name provided.
- ///
- /// The view.
- /// Value of the 'name' attribute of the element.Also used to derive the 'id' attribute.
- public static TextBox TextBox(this IViewDataContainer view, string name)
- {
- return new TextBox(name).Value(view.ViewData.Eval(name));
- }
- … …
tainer 的Extension Method:
看一下return new TextBox(name).Value(view.ViewData.Eval(name));所以這里就成了TextBox定義方法鏈的***步.
FluentHtml與連續(xù)接口總結(jié)
為了能夠在View中能夠簡(jiǎn)潔清晰的構(gòu)造HTML元素,Asp.net MVC中通過(guò)htmlHelper.InputHelper來(lái)實(shí)現(xiàn)頁(yè)面元素的構(gòu)造. 頁(yè)面層所使用的<%= Html.TextBox("username") %>,HTML也是htmlHelper的Extension Method.相比較起來(lái),htmlHelper提供了基礎(chǔ)的頁(yè)面控件定義和構(gòu)造,而FluentHTML表現(xiàn)的更為靈活.除了FluentHTML,著名的Spark View Engine也有類(lèi)似的實(shí)現(xiàn),大家可以關(guān)注一下.
【編輯推薦】
- VS2010 Beta 1的ASP.NET MVC安裝包發(fā)布
- ASP.NET中性能和擴(kuò)展性的秘密
- ASP.NET 3.5圖表控件親密接觸
- 自己動(dòng)手實(shí)現(xiàn)Asp.net的MVC框架
- ASP.NET中防止用戶(hù)多次登錄的方法
文章題目:淺談ASP.NETMVC中的FluentHtml與連續(xù)接口
標(biāo)題來(lái)源:http://m.fisionsoft.com.cn/article/dhohisi.html


咨詢(xún)
建站咨詢(xún)
