• [原]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"]即可。

  • 相关阅读:
    微软企业库5.0 学习之路——第七步、Cryptographer加密模块简单分析、自定义加密接口及使用—上篇
    微软企业库5.0 学习之路——第六步、使用Validation模块进行服务器端数据验证
    微软企业库5.0 学习之路——第五步、介绍EntLib.Validation模块信息、验证器的实现层级及内置的各种验证器的使用方法——下篇
    微软企业库5.0 学习之路——第五步、介绍EntLib.Validation模块信息、验证器的实现层级及内置的各种验证器的使用方法——中篇
    微软企业库5.0 学习之路——第五步、介绍EntLib.Validation模块信息、验证器的实现层级及内置的各种验证器的使用方法——上篇
    微软企业库5.0 学习之路——第四步、使用缓存提高网站的性能(EntLib Caching)
    微软企业库5.0 学习之路——第二步、使用VS2010+Data Access模块建立多数据库项目
    微软企业库5.0 学习之路——第一步、基本入门
    linux时间管理 之 jiffies
    IOCTL函数用法
  • 原文地址:https://www.cnblogs.com/think8848/p/2175432.html
Copyright © 2020-2023  润新知