MVC4 DataType.Date EditorFor won't display dat

2019-01-01 07:44发布

问题:

I\'m using the DataType.Date attribute on my model and an EditorFor in my view. This is working fine in Internet Explorer 8 and Internet Explorer 9, but in Google Chrome it is showing a date picker and instead of displaying the value it just displays \"Month/Day/Year\" in faded gray text.

Why won\'t Google Chrome display the value?

Model:

[DataType(DataType.Date)]
public Nullable<System.DateTime> EstPurchaseDate { get; set; }

View:

<td class=\"fieldLabel\">Est. Pur. Date</td>
<td class=\"field\">@Html.EditorFor(m=>m.EstPurchaseDate)</td>

\"Chrome\"

\"Internet

回答1:

When you decorate a model property with [DataType(DataType.Date)] the default template in ASP.NET MVC 4 generates an input field of type=\"date\":

<input class=\"text-box single-line\" 
       data-val=\"true\" 
       data-val-date=\"The field EstPurchaseDate must be a date.\"
       id=\"EstPurchaseDate\" 
       name=\"EstPurchaseDate\" 
       type=\"date\" value=\"9/28/2012\" />

Browsers that support HTML5 such Google Chrome render this input field with a date picker.

In order to correctly display the date, the value must be formatted as 2012-09-28. Quote from the specification:

value: A valid full-date as defined in [RFC 3339], with the additional qualification that the year component is four or more digits representing a number greater than 0.

You could enforce this format using the DisplayFormat attribute:

[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = \"{0:yyyy-MM-dd}\", ApplyFormatInEditMode = true)]
public Nullable<System.DateTime> EstPurchaseDate { get; set; }


回答2:

In MVC5.2, add Date.cshtml to folder ~/Views/Shared/EditorTemplates:

@model DateTime?
@{
    IDictionary<string, object> htmlAttributes;
    object objAttributes;
    if (ViewData.TryGetValue(\"htmlAttributes\", out objAttributes))
    {
        htmlAttributes = objAttributes as IDictionary<string, object> ?? HtmlHelper.AnonymousObjectToHtmlAttributes(objAttributes);
    }
    else
    {
        htmlAttributes = new RouteValueDictionary();
    }
    htmlAttributes.Add(\"type\", \"date\");
    String format = (Request.UserAgent != null && Request.UserAgent.Contains(\"Chrome\")) ? \"{0:yyyy-MM-dd}\" : \"{0:d}\";
    @Html.TextBox(\"\", Model, format, htmlAttributes)
}


回答3:

As an addition to Darin Dimitrov\'s answer:

If you only want this particular line to use a certain (different from standard) format, you can use in MVC5:

@Html.EditorFor(model => model.Property, new {htmlAttributes = new {@Value = @Model.Property.ToString(\"yyyy-MM-dd\"), @class = \"customclass\" } })


回答4:

In MVC 3 I had to add:

using System.ComponentModel.DataAnnotations;

among usings when adding properties:

[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = \"{0:yyyy-MM-dd}\", ApplyFormatInEditMode = true)]

Especially if you are adding these properties in .edmx file like me. I found that by default .edmx files don\'t have this using so adding only propeties is not enough.



回答5:

If you remove [DataType(DataType.Date)] from your model, the input field in Chrome is rendered as type=\"datetime\" and won\'t show the datepicker either.



回答6:

I still had an issue with it passing the format yyyy-MM-dd, but I got around it by changing the Date.cshtml:

@model DateTime?

@{
    string date = string.Empty;
    if (Model != null)
    {
        date = string.Format(\"{0}-{1}-{2}\", Model.Value.Year, Model.Value.Month, Model.Value.Day);
    }

    @Html.TextBox(string.Empty, date, new { @class = \"datefield\", type = \"date\"  })
}


回答7:

Reply to MVC4 DataType.Date EditorFor won\'t display date value in Chrome, fine in IE

In the Model you need to have following type of declaration:

[DataType(DataType.Date)]
public DateTime? DateXYZ { get; set; }

OR

[DataType(DataType.Date)]
public Nullable<System.DateTime> DateXYZ { get; set; }

You don\'t need to use following attribute:

[DisplayFormat(DataFormatString = \"{0:yyyy-MM-dd}\", ApplyFormatInEditMode = true)]

At the Date.cshtml use this template:

@model Nullable<DateTime>
@using System.Globalization;

@{
    DateTime dt = DateTime.Now;
    if (Model != null)
    {
        dt = (System.DateTime)Model;

    }

    if (Request.Browser.Type.ToUpper().Contains(\"IE\") || Request.Browser.Type.Contains(\"InternetExplorer\"))
    {
        @Html.TextBox(\"\", String.Format(\"{0:d}\", dt.ToShortDateString()), new { @class = \"datefield\", type = \"date\" })
    }
    else
    {
        //Tested in chrome
        DateTimeFormatInfo dtfi = CultureInfo.CreateSpecificCulture(\"en-US\").DateTimeFormat;
        dtfi.DateSeparator = \"-\";
        dtfi.ShortDatePattern = @\"yyyy/MM/dd\"; 
        @Html.TextBox(\"\", String.Format(\"{0:d}\", dt.ToString(\"d\", dtfi)), new { @class = \"datefield\", type = \"date\" })
    } 
}

Have fun! Regards, Blerton



回答8:

If you need to have control over the format of the date (in other words not just the yyyy-mm-dd format is acceptable), another solution could be adding a helper property that is of type string and add a date validator to that property, and bind to this property on UI.

    [Display(Name = \"Due date\")]
    [Required]
    [AllowHtml]
    [DateValidation]
    public string DueDateString { get; set; }

    public DateTime? DueDate 
    {
        get
        {
            return string.IsNullOrEmpty(DueDateString) ? (DateTime?)null : DateTime.Parse(DueDateString);
        }
        set
        {
            DueDateString = value == null ? null : value.Value.ToString(\"d\");
        }
    }

And here is a date validator:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public class DateValidationAttribute : ValidationAttribute
{
    public DateValidationAttribute()
    {
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value != null)
        {
            DateTime date;

            if (value is string)
            {
                if (!DateTime.TryParse((string)value, out date))
                {
                    return new ValidationResult(validationContext.DisplayName + \" must be a valid date.\");
                }
            }
            else
                date = (DateTime)value;

            if (date < new DateTime(1900, 1, 1) || date > new DateTime(3000, 12, 31))
            {
                return new ValidationResult(validationContext.DisplayName + \" must be a valid date.\");
            }
        }
        return null;
    }
}