2011-04-03 7 views
8

estoy usando ASP.NET MVC 3 RTM, y tengo un modelo de vista así:error de encuadernación en el modelo personalizado Minder elimina el valor que el usuario introduce

public class TaskModel 
{ 
    // Lot's of normal properties like int, string, datetime etc. 
    public TimeOfDay TimeOfDay { get; set; } 
} 

La propiedad TimeOfDay es una estructura a medida que tener, que es bastante simple, así que no lo estoy incluyendo aquí. He creado una carpeta de modelo personalizada para enlazar esta estructura. El aglutinante modelo es bastante simple:

public class TimeOfDayModelBinder : IModelBinder 
{ 
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     var result = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); 
     try 
     { 
      // Let the TimeOfDay struct take care of the conversion from string. 
      return new TimeOfDay(result.AttemptedValue, result.Culture); 
     } 
     catch (ArgumentException) 
     { 
      bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Value is invalid. Examples of valid values: 6:30, 16:00"); 
      return bindingContext.Model; // Also tried: return null, return value.AttemptedValue 
     } 
    } 
} 

Mi ligante modelo personalizado funciona bien, pero el problema es cuando el valor proporcionado por el usuario No se pudo convertir o analizarlo. Cuando esto sucede (cuando el constructor TimeOfDay arroja un ArgumentException), agrego un error de modelo que se muestra correctamente en la vista, pero el valor que escribió el usuario, que no se pudo convertir, se pierde. El cuadro de texto en el que el usuario tipeó el valor, está simplemente vacío, y en el origen HTML, el atributo de valor se establece en una cadena vacía: "".

EDIT: Me pregunto si podría ser mi editor de plantillas que está haciendo algo mal, así que estoy incluyendo aquí:

@model Nullable<TimeOfDay> 
@if (Model.HasValue) 
{ 
    @Html.TextBox(string.Empty, Model.Value.ToString()); 
} 
else 
{ 
    @Html.TextBox(string.Empty); 
} 

¿Cómo puedo hacer que el valor no se pierde cuando ocurre un error de enlace, entonces el usuario puede corregir el valor?

Respuesta

17

Aha! ¡Finalmente encontré la respuesta! This blog post dio la respuesta. Lo que me falta es llamar al ModelState.SetModelValue() en mi carpeta modelo. Entonces el código sería así:

public class TimeOfDayModelBinder : IModelBinder 
{ 
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     var result = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); 
     try 
     { 
      // Let the TimeOfDay struct take care of the conversion from string. 
      return new TimeOfDay(result.AttemptedValue, result.Culture); 
     } 
     catch (ArgumentException) 
     { 
      bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Value is invalid. Examples of valid values: 6:30, 16:00"); 
      // This line is what makes the difference: 
      bindingContext.ModelState.SetModelValue(bindingContext.ModelName, result); 
      return bindingContext.Model; 
     } 
    } 
} 

Espero que esto salve a alguien más de las horas de frustración que he pasado.

Cuestiones relacionadas