2012-06-30 24 views
54

¿Cómo puedo forzar el formato de datetime en asp.net mvc 4? En el modo de visualización, se muestra como quiero, pero en el modelo de edición no aparece. estoy usando displayfor y editorfor y applyformatineditmode = true con DataFormatString = "{0: dd/mm/aaaa}" Lo que he intentado:Formato datetime en asp.net mvc 4

  • globalización en web.config (dos de ellos) con mi cultura y uiculture.
  • modificar la cultura y uiculture en Application_Start()
  • encargo modelbinder de fecha y hora

no tengo ni idea de cómo forzar y que necesito para introducir la fecha como dd/mm/aaaa no es el predeterminado.

MÁS INFORMACIÓN: mi modelo de vista es como esto

[DisplayName("date of birth")] 
    [DataType(DataType.Date)] 
    [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)] 
    public DateTime? Birth { get; set; } 

en vista utilizo @Html.DisplayFor(m=>m.Birth) pero esto funciona como se esperaba (veo el formato) y para introducir la fecha utilizo @Html.EditorFor(m=>m.Birth) pero si lo intento y entrada algo como 13/12/2000 falla con el error de que no es una fecha válida (12/13/2000 y 2000/12/13 funcionan como se esperaba pero necesito dd/MM/aaaa).

El encuadernador personalizado se llama en application_start() b/c No sé dónde más.

Usando <globalization/> He intentado con culture="ro-RO", uiCulture="ro" y otras culturas que me darían dd/mm/aaaa. También han tratado de ponerlo en una base por hilo en Application_Start() (hay una gran cantidad de ejemplos aquí, sobre cómo hacer esto)


Por todo lo que va a leer esta pregunta: Parece la respuesta de Darin Dimitrov funcionará siempre que no tenga la validación del cliente. Otro enfoque es usar validación personalizada, incluida la validación del lado del cliente. Me alegro de haber descubierto esto antes de volver a crear toda la aplicación.

+0

¿Podrían presentar una poco más información? Su modelo, controlador y vista? También proporcione un ejemplo de los diferentes resultados que obtiene entre la plantilla de visualización y editor. También tenga en cuenta que la cultura se establece por hilo. Mencionaste algo sobre 'Application_Start', pero esto se ejecuta solo una vez, cuando se inicia la aplicación. ¿Qué pasa con las solicitudes posteriores? ¿Cómo estás estableciendo la cultura para ellos? –

+0

¡application_start se ejecuta solo una vez! ¡Use application_beginRequest en su lugar! – Nas

+0

Nas, ¿dónde sería application_beginRequest? Solo veo application_start en Global. En mvc 4 las cosas comenzaron a ser un poco diferentes, entonces mvc 3 – amb

Respuesta

96

Ahhhh, ahora está claro. Parece que tienes problemas para vincular el valor. No con mostrarlo en la vista. De hecho, ese es el error del encuadernador de modelo predeterminado. Puede escribir y usar uno personalizado que tenga en cuenta el atributo [DisplayFormat] en su modelo. He ilustrado un aglomerante tal modelo costumbre aquí: https://stackoverflow.com/a/7836093/29407


Al parecer, todavía persisten algunos problemas. Aquí está mi configuración completa que funciona perfectamente bien en ASP.NET MVC 3 & 4 RC.

Modelo:

public class MyViewModel 
{ 
    [DisplayName("date of birth")] 
    [DataType(DataType.Date)] 
    [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)] 
    public DateTime? Birth { get; set; } 
} 

controlador:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     return View(new MyViewModel 
     { 
      Birth = DateTime.Now 
     }); 
    } 

    [HttpPost] 
    public ActionResult Index(MyViewModel model) 
    { 
     return View(model); 
    } 
} 

Vista:

@model MyViewModel 

@using (Html.BeginForm()) 
{ 
    @Html.LabelFor(x => x.Birth) 
    @Html.EditorFor(x => x.Birth) 
    @Html.ValidationMessageFor(x => x.Birth) 
    <button type="submit">OK</button> 
} 

Registro de la carpeta de modelo personalizado en Application_Start:

ModelBinders.Binders.Add(typeof(DateTime?), new MyDateTimeModelBinder()); 

Y el modelo personalizado en sí ligante:

public class MyDateTimeModelBinder : DefaultModelBinder 
{ 
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     var displayFormat = bindingContext.ModelMetadata.DisplayFormatString; 
     var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); 

     if (!string.IsNullOrEmpty(displayFormat) && value != null) 
     { 
      DateTime date; 
      displayFormat = displayFormat.Replace("{0:", string.Empty).Replace("}", string.Empty); 
      // use the format specified in the DisplayFormat attribute to parse the date 
      if (DateTime.TryParseExact(value.AttemptedValue, displayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out date)) 
      { 
       return date; 
      } 
      else 
      { 
       bindingContext.ModelState.AddModelError(
        bindingContext.ModelName, 
        string.Format("{0} is an invalid date format", value.AttemptedValue) 
       ); 
      } 
     } 

     return base.BindModel(controllerContext, bindingContext); 
    } 
} 

Ahora, no importa lo que la cultura que ha configurado en su web.config (<globalization> elemento) o la cultura hilo actual, el aglutinante modelo personalizado utilizará el atributo de DisplayFormat formato de fecha al analizar las fechas anulables.

+1

Este es el que he usado pero sin suerte. Lo he registrado con datetime y datetime? Ni siquiera muestra mi mensaje de error, así que no creo que se esté usando. – amb

+1

Entonces supongo que tendrá que mostrar su código completo permitiéndonos reproducir el problema, porque estoy usando este modelo de carpeta sin ningún problema. –

+0

Por curiosidad, ¿qué tipo de proyecto MVC es (4 o 3)? – amb

0

Gracias Darin, Para mí, para poder escribir con el método de crear, Sólo funcionaba después de que modificara el código bindModel a:

public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
{ 
    var displayFormat = bindingContext.ModelMetadata.DisplayFormatString; 
    var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); 

    if (!string.IsNullOrEmpty(displayFormat) && value != null) 
    { 
     DateTime date; 
     displayFormat = displayFormat.Replace("{0:", string.Empty).Replace("}", string.Empty); 
     // use the format specified in the DisplayFormat attribute to parse the date 
     if (DateTime.TryParse(value.AttemptedValue, CultureInfo.GetCultureInfo("en-GB"), DateTimeStyles.None, out date)) 
     { 
      return date; 
     } 
     else 
     { 
      bindingContext.ModelState.AddModelError(
       bindingContext.ModelName, 
       string.Format("{0} is an invalid date format", value.AttemptedValue) 
      ); 
     } 
    } 

    return base.BindModel(controllerContext, bindingContext); 
} 

la esperanza que esto podría ayudar a alguien más ...

0

problemas de validación de cliente pueden ocurrir debido a MVC error (incluso en MVC 5) en la que jquery.validate.unobtrusive.min.jsno acepta el formato de fecha/fecha y hora de cualquier manera. Desafortunadamente, tienes que resolverlo manualmente.

Mi solución finalmente trabajar:

$(function() { 
    $.validator.methods.date = function (value, element) { 
     return this.optional(element) || moment(value, "DD.MM.YYYY", true).isValid(); 
    } 
}); 

Tienes que incluir antes:

@Scripts.Render("~/Scripts/jquery-3.1.1.js") 
@Scripts.Render("~/Scripts/jquery.validate.min.js") 
@Scripts.Render("~/Scripts/jquery.validate.unobtrusive.min.js") 
@Scripts.Render("~/Scripts/moment.js") 

Puede instalar moment.js usando:

Install-Package Moment.js