zoukankan      html  css  js  c++  java
  • [原]ASP.NET MVC 3 Razor 表单还能再直观点

    转载请注明作者(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()的方式很难能做到所见即所得的效果,而且在一个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"]即可。

  • 相关阅读:
    追星必备神器 -- 爱豆APP
    关于结对编程项目(Sports club 三)
    关于结对编程项目(Sports club 二)
    关于结对编程项目(Sports club)
    关于对当前大学生的痛点分析
    关于wc项目的简单基本前期制作。
    个人项目作品设计——Sports history
    简单四则运算
    关于介绍手机k歌娱乐软件
    结对项目(3)
  • 原文地址:https://www.cnblogs.com/think8848/p/2175432.html
Copyright © 2011-2022 走看看