[原]ASP.NET MVC 3 Razor 表單還能再直觀點

來源:互聯網
上載者:User

轉載請註明作者(think8848)和出處(http://think8848.cnblogs.com)

依照本人慣例,開篇先說些與主題無關的話:本來打算把寫部落格的這個習慣堅持下去,就算不能出精品,也能出一些水貨,對於某些小問題提供點解決方案,但是今年的8月真可謂是多事之“秋”,很多事情都湊到一起去了,幾乎沒有時間學習新的東西,更別說去寫部落格了,9月眼看要過去一半了,昨天才憋出一個小東西,覺得還稍能濫竽充數下。

打算用ASP.NET MVC實現公司的某產品了,昨天遇到一個問題:在異常發生時轉回提交前的頁面後,原來輸入的內容不見了,這可是個大問題,記得以前我在寫《ASP.NET MVC異常處理方案》一文時已經解決了這個問題,怎麼又看不見提交前的輸入了呢,把以前的代碼開啟後發現了問題所在:

在當前的代碼中表單的代碼為:

<input id="txtName" name="Name" type="text" />

而之前能出現效果的表單代碼為:

@Html.TextBoxFor(x => x.Name)

稍經測試,就發現,使用Html的擴充方法產生的<input>標籤可以獲得提交之前的值,但是自已手寫的則不行,所以這個TextBox擴充方法中肯定有某種機制,能自動將值填進<input>標籤中。一開始和同事討論後覺得,使用@Html.TextBoxFor方法有一個好處,那就是如果更換了Name屬性的名稱,VS可以自動重構代碼,使*.cshtml代碼的x.Name自動更新至新的屬性名稱,經測試後發現原來不是想的這麼回事,修改了Name屬性的名稱,如:PName,使用VS重構代碼,發現在視圖中屬性名稱居然沒有改過來;而且如果使用Html的擴充方法,似乎也有一些問題,最重要一點就是不直觀,在目前的Razor引擎中還不太明顯,反正也沒有設計器,但是如果以後有了Razor引擎有了設計器功能,基本可以斷定的是,使用@Html.TextBoxFor()的方式很難能做到所見即所得 (WYSIWYG)的效果,而且在一個cshtml頁面中,即時不能使用設計器,看代碼時如果視圖上使用@Html.XXX也不是很直觀,既然使用Html擴充方法的方式即不能有利於重構代碼,又不直觀,那麼使用Html標籤的理由似乎就變的充分多了,如果使用這種方法,即使不會C#的人也可以寫出來頁面。

在這種想法的驅動下,想出一個辦法:自已實現一個填充標籤值的擴充方法。於是開啟ASP.NET MVC 3原始碼,看看在這個TextBox內部到底在做些什麼,為什麼它可以把模型(ViewData.Model)中的值,以及ViewData.ModelState中的值填充到標籤中,一步一步查下來,發現原來實現方法比較簡單,直接上代碼:

    public static class HtmlValueExtension    {        public static MvcHtmlString Value<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression)        {            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);            return Value(html, metadata.PropertyName);        }        public static MvcHtmlString Value(this HtmlHelper html, string name)        {            string attemptedValue = null;            ModelState modelState;            if (html.ViewData.ModelState.TryGetValue(name, out modelState))            {                if (modelState.Value != null)                {                    attemptedValue = modelState.Value.ConvertTo(typeof(string), null /* culture */).ToString();                }            }            return new MvcHtmlString(attemptedValue ?? Convert.ToString(html.ViewData.Eval(name), CultureInfo.CurrentCulture));        }    }

定義一個HtmlHelper<TModel>的擴充方法Value<TModel,TProperty>,然後根據Lambda運算式擷取到指定屬性的中繼資料,優先考慮從ModelState中拿出對應的資料,也就是提交前頁面表單資料,如果這個資料為null,則嘗試ViewData.Model中指定的資料,很簡單吧:)

有了這個類,在頁面上使用如下代碼調用:

                <input id="txtDeptName" name="Name" type="text" value="@Html.Value(x => x.Name)"/>

這樣,就可以達到與@Html.TextBox()一樣的效果了,但是從視圖的代碼角度來說,直觀了不少,而且如果以後Razor引擎有了設計器,估計也可以不用調試也能看到頁面效果了。  

最後再友情提示下,如果您在一個Razor的視圖中定義了一個表單標籤,這個表單標籤的值並不對應Model的某個屬性,這時如果您想擷取提交前的值話,使用Request.Params["TagName"]即可。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.