【问题标题】:How to format the value in a strongy typed view when using ASP.Net MVC's Html.TextBoxFor使用 ASP.Net MVC Html.TextBoxFor 时如何在强类型视图中格式化值
【发布时间】:2011-01-06 11:38:37
【问题描述】:

我正在尝试使用强类型视图的值来格式化由 ASP.Net MVC 的 TextBoxFor 呈现的日期。日期可以为空,因此如果为空,我希望看到一个空白值,否则我希望以 MM/dd/yyyy 格式查看它。

<%= Html.TextBoxFor(model => model.BirthDate, new { style = "width: 75px;" })%>

谢谢,
保罗·斯佩兰萨

【问题讨论】:

  • 你在 asp.net mvc 2 RC 中?
  • 凹凸:你有没有想过如何做到这一点?
  • 这里有同样的问题。强视图上不能有自定义样式
  • MVC3 的解决方案是什么?

标签: asp.net-mvc format html-helper


【解决方案1】:

您是否尝试过只传递您想要的日期格式?

Html.TextBoxFor(model => model.BirthDate.ToString("MM/dd/yyyy"), 
                new { style = "width: 75px;" })

【讨论】:

  • 如果我使用它 model.BirthDate.Value.ToString("MM/dd/yyyy")) %> 我得到例外“模板可以使用仅适用于字段和属性访问器表达式。”
  • lambda 的要点是使用表达式从模型中为文本框生成一个 id。这是个坏主意。
  • 他对每个显示日期的文本框都这样做了吗?不是很干。
【解决方案2】:

您是否尝试过强制当前线程应用程序的文化?您可以在 web.config 中使用这一行(在标签中)覆盖它:

<!-- Default resource files are set here. The culture will also change date format, decimal, etc... -->
<globalization enableClientBasedCulture="false" culture="en-US" uiCulture="en-US"/>

【讨论】:

    【解决方案3】:

    首先,添加这个扩展来获取属性路径:

    public static string GetPropertyPath<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> property)
    {                       
         Match match = Regex.Match(property.ToString(), @"^[^\.]+\.([^\(\)]+)$");
         return match.Groups[1].Value;
    }
    

    比为 HtmlHalper 添加这个扩展:

    public static MvcHtmlString DateBoxFor<TEntity>(
                this HtmlHelper helper,
                TEntity model,
                Expression<Func<TEntity, DateTime?>> property,
                object htmlAttributes)
            {
                DateTime? date = property.Compile().Invoke(model);
    
                // Here you can format value as you wish
                var value = date.HasValue ? date.Value.ToShortDateString() : string.Empty;
                var name = ExpressionParseHelper.GetPropertyPath(property);
    
                return helper.TextBox(name, value, htmlAttributes);
            }
    

    你还应该添加这个 jQuery 代码:

    $(function() {
        $("input.datebox").datepicker();
    });
    

    datepicker 是一个 jQuery 插件。

    现在你可以使用它了:

     <%= Html.DateBoxFor(Model, (x => x.Entity.SomeDate), new { @class = "datebox" }) %>
    

    【讨论】:

      【解决方案4】:

      这是一个肮脏的黑客,但它似乎工作。

      <%= Html.TextBoxFor(model => model.SomeDate,
          new Dictionary<string, object> { { "Value", Model.SomeDate.ToShortDateString() } })%>
      

      您获得模型绑定,并且能够使用格式化字符串覆盖文本字段的 HTML“值”属性。

      【讨论】:

      • 如果这在 MVC 1 中有效,它在 MVC 2 中已停止工作。默认输出似乎优先于 value 属性。不是我预期的那样,但无论尝试将其作为Dictionary&lt;string, object&gt; 或匿名对象(例如new { value = Model.SomeDate.ToShortDateString() }),它都不起作用。
      【解决方案5】:

      一个简单的解决方案是不使用强类型帮助器。

      <%= Html.TextBox("StartDate", string.Format("{0:d}", Model.StartDate)) %>
      

      【讨论】:

      • 对于复杂模型(例如,Model.SubModel.SubSubModel),您必须执行生成带有适当前缀的 id/name 的逻辑。否则,您会破坏模型状态内的绑定和验证范围。
      【解决方案6】:

      您可以通过使用custom editor templateHtml.EditorFor() 而不是Html.TextBoxFor() 来保持强类型。

      在您的 /Views/Shared 文件夹中创建一个新的 EditorTemplates 文件夹,并添加一个名为 DateTime 的新 MVC 2 View User Control .ascx。添加以下内容

      <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<System.DateTime?>" %>
      <%= Html.TextBox("", (Model.HasValue ? Model.Value.ToString("MM/dd/yyyy") : string.Empty)) %>
      

      那么在你看来使用

      <%= Html.EditorFor(model => model.BirthDate)%></p>
      

      不用担心“”,命名仍然可以正常工作。

      如果您以与默认应用程序文化不同的文化格式显示 DateTime,那么您将需要 change the culture information 或创建一个 custom model binder 以便模型绑定在回发 DateTime 时工作.

      【讨论】:

      • 将视图强类型化到模型是有意义的,但模型具有诸如“DateTime?”之类的类型就没有意义了
      • @CRice 通过在 ViewModel 中传递 DateTime,它允许 View 负责格式化出生日期。标准视图可能会显示完整日期,而移动视图可能会显示缩短版本。
      • 如果您绝对无法从控制器级别确定某些内容,那很好,但这是一种极端情况,通常您的解决方案对于仅将日期呈现为文本将是矫枉过正的。
      • @CRice 上面提供了一种可重用的方法,在两行代码中以自定义格式显示 DateTime,同时保持强类型。我几乎不会称之为矫枉过正。我已经更新了我的答案,删除了与不同文化打交道的额外信息,因为这可能会导致混淆。
      • 这是集中日期格式化逻辑并保持视图愚蠢的最聪明的方法 - 正如大多数人所投票的那样。
      【解决方案7】:

      我使用了一些自定义助手,并已在 MVC 2 和 3 中成功使用它们(代码也为 on Snipplr)。当我使用 jQuery-ui 日期选择器时,助手有一些 css 逻辑,但可以很容易地删除。

      public static MvcHtmlString DateTextBoxFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression, string formatString, object htmlAttributes)
          {
              var metadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
              string format = String.IsNullOrEmpty(formatString) ? "M/d/yyyy" : formatString;
              DateTime date = metadata.Model == null ? new DateTime() : DateTime.Parse(metadata.Model.ToString());
              string value = date == new DateTime() ? String.Empty : date.ToString(format);
              RouteValueDictionary attributes = new RouteValueDictionary(htmlAttributes);
              string datePickerClass = "date-selector";
              if (attributes.ContainsKey("class"))
              {
                  string cssClass = attributes["class"].ToString();
                  attributes["class"] = cssClass.Insert(cssClass.Length, " " + datePickerClass);
              }
              else
              {
                  attributes["class"] = datePickerClass;
              }
              return helper.TextBox(ExpressionHelper.GetExpressionText(expression), value, attributes);
          }
      
          public static MvcHtmlString DateTextBoxFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression)
          {
              return DateTextBoxFor<TModel, TValue>(helper, expression, String.Empty, null);
          }
      
          public static MvcHtmlString DateTextBoxFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression, string formatString)
          {
              return DateTextBoxFor<TModel, TValue>(helper, expression, formatString, null);
          }
      

      【讨论】:

      • 拍摄,刚刚看到@Сергій 发布了类似的内容。对不起,@Сергій!
      【解决方案8】:

      说真的,为什么视图必须这样做?

      将具有日期时间对象的核心模型映射到 mvc 视图模型。

      //core model
      public class Person
      {
          public DateTime? BirthDate { get; set;}
      }
      
      //view model
      public class PersonForm
      {
          public string BirthDate { get; set; }
      }
      

      所以映射可能看起来像:

      public interface IDomainToViewMapper<TModel, TViewModel>
      {
          /// <summary>
          /// Use an automapper or custom implementation to map domain model to presentation model.
          /// </summary>
          /// <param name="source">domain model</param>
          /// <returns>presentation model</returns>
          TViewModel MapDomainToView(TModel source);        
      }
      
      public interface IPersonMapper : IDomainToViewMapper<Person, PersonForm>
      {
      }
      
      public class PersonMapper : IPersonMapper
      {
          #region IDomainToViewMapper<Person,PersonForm> Members
      
          public PersonForm MapDomainToView(Person source)
          {
              PersonForm p = new PersonForm();
      
              if (source.BirthDate.HasValue)
              {
                  p.BirthDate = source.BirthDate.Value.ToShortDateString();
              }
      
              return p;
          }
      
          #endregion
      }
      

      您的控制器操作可能如下所示:

          public ActionResult Index()
          {
              Person person = //get person;
              var personForm = _personMapper.MapDomainToView(person);
      
              return View(personForm)
          }
      

      那时您根本不需要更改视图示例。


      来自第 2 章,MVC 2 实战(曼宁)

      public class CustomerSummary
      {
      public string Name { get; set; }
      public bool Active { get; set; }
      public string ServiceLevel { get; set; }
      public string OrderCount { get; set;}
      public string MostRecentOrderDate { get; set; }
      }
      

      这个模型故意简单;它主要由字符串组成。这就是我们所代表的, 毕竟:页面上的文字。显示此对象中数据的逻辑将是 直截了当;视图只会输出它。 演示模型旨在 尽量减少视图中的决策。

      【讨论】:

      • 通过允许视图负责格式化日期时间,您可以正常视图显示“2010 年 1 月 20 日”和不同的移动视图显示“1/20/10”,而无需维护重复控制器代码。该视图可能还希望显示年龄和出生日期。
      • 这个问题没有提到同一模型需要不同的视图。控制器也有责任从视图中删除决策,而视图只是渲染模型。
      • 控制器是轻量级协调器。我真的不认为控制器有责任处理格式化。绝对是辅助逻辑。
      • 我同意控制器是轻量级的。在我的情况下,控制器会调用映射(请参阅我的答案),这会将对象转换为呈现方式。
      • 恕我直言,视图应该负责格式化。我同意尼克关于有一个助手或几个助手的观点,视图可以从中挑选。我一直认为控制器只做两件事 - 从数据源获取数据并将其传递给适当的视图。
      【解决方案9】:

      只需将它命名为它正在寻找的东西。喜欢:

      Html.TextBox("Person.StartTime",Person.StartTime.ToShortDateString());
      

      当它返回到控制器时,你的模型的值将是有界的。

      【讨论】:

        【解决方案10】:

        您可以考虑以下针对日期时间数据的 TextBoxFor 扩展方法示例:

            public static MvcHtmlString CalenderTextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
                {
                    Func<TModel, TProperty> deleg = expression.Compile();
                    var result = deleg(htmlHelper.ViewData.Model);
        
                    string value = null;
        
                    if (result.ToString() == DateTime.MinValue.ToString())
                        value = string.Empty;
                    else
                        value = string.Format("{0:M-dd-yyyy}", result);
        
                    return htmlHelper.TextBoxFor(expression, new { @class = "datepicker text", Value = value });
               }
        

        【讨论】:

          【解决方案11】:

          MVC4http://msdn.microsoft.com/en-us/library/hh833694.aspx

          @Html.TextBoxFor(model => model.YOUR_DATE, "{0:MM/dd/yyyy}")
          

          【讨论】:

          • 这也帮助我解决了在数据注释不适用于 TextBoxFor 时格式化日期的问题
          猜你喜欢
          • 1970-01-01
          • 2015-08-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多