2011-12-22 10 views
8

En términos simples, ¿qué hace UpdateModel(), así como TryUpdateModel()? Parece que no puedo encontrar (en SO o en la web) ninguna explicación clara de lo que realmente hace (en términos claros), solo personas que tienen problemas para usarlo.¿Qué hace UpdateModel()?

El intellisense de VisualStudio tampoco me está ayudando. La razón por la que pido es porque, digamos, si tengo esto en mi controlador:

[HttpPost] 
public ActionResult Index(UserViewModel vm, FormCollection form) 
{  
    var statesCheckBoxes = form["StatesList"];  

    vm.BA.StatesTraveledTo = statesCheckBoxes.Split(',').ToList<string>(); 

    return View(vm); 
} 

¿verdad ya actualizar mi modelo mediante el establecimiento de vm.BA.StatesTraveledTo? ¿Por qué necesito ejecutar UpdateModel? Además, cuando en realidad trato de hacer lo siguiente:

[HttpPost] 
public ActionResult Index(UserViewModel vm, FormCollection form) 
{  
    var statesCheckBoxes = form["StatesList"];  

    vm.BA.StatesTraveledTo = statesCheckBoxes.Split(',').ToList<string>(); 

    UpdateModel(vm); // IS THIS REDUNDANT TO THE PREVIOUS LINE? 

    return View(vm); 
} 

Nada parece suceder en que cuando examino el valor de la ModelState (después de ejecutar UpdateModel()), no veo nada que indique que cualquier cosa ha cambiado. No veo una nueva clave en el diccionario ModelState.

Realmente confundido. ¡Gracias!

Editar:

Publicar el código fuente de las clases ViewModel y modelo:

public class UserViewModel 
{ 
    public BankAccount BA { get; set; } 
} 

public class BankAccount 
{ 
    public Person User { get; set; } 
    public List<string> StatesTraveledTo { get; set; } 
} 

public class Person 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public int Age { get; set; } 
} 
+1

Aquí está el código fuente para ello: http://aspnet.codeplex.com/SourceControl/changeset/view/72551#266451 es bastante simple ,, simplemente crea un ModelBindingContext y lo enlaza –

+1

Además, es un tanto Es raro que pase el mismo objeto que recibió como entrada en una acción en la vista, sucede pero es raro y esto no parece ser uno de esos usos. Por lo general, toma como entrada un objeto que representa los datos publicados y luego crea un modelo separado para la vista –

+0

Gracias. La razón por la que devuelvo el modelo a la vista es para fines de validación. Entonces, en caso de que falle la validación, quiero que el modelo y sus valores pasen a la vista para que los campos del formulario se vuelvan a llenar y se muestre un mensaje de error. Lo siento, creo que con el código que mostré, puede que no parezca un ejemplo práctico. – SaltProgrammer

Respuesta

5

lo que ocurre cuando se escribe

public ActionResult Index(UserViewModel vm) 
{ } 

y cuando se inspecciona en el ActionResult encuentra que vm contiene valores que usted fijó desde el punto de vista. es porque mvc dirige el encuadernador para extraer valores de diferentes fuentes (colección de formularios, valores de ruta, cadena de consulta, etc.) y rellenar valores de su modelo. Pero para que esto suceda, sus claves de formulario deben coincidir con el nombre de las propiedades en su modelo y, si ese es el caso, su modelo se llena correctamente. ahora llegamos a la pregunta real: ¿qué hace UpdateModel? La respuesta simple no es más que un modelo vinculante. La diferencia es solo que lo llamas explícitamente.Lo anterior ActionResult puede reescribirse como el uso de UpdateModel

Public ActionResult Index() 
{ 
    UserViewModel vm = new UserViewModel(); 
    UpdateModel(vm);// it will do same thing that was previously handled automatically by mvc 
} 

Ahora, lo que no fue manejado por la unión no será manejada por el modelo explícito de unión, así modelo automático porque no es el problema con el modelo de ligante su problema con su html . con modelos de vista anidadas como la suya, los nombres de campos de formulario deben ser cuidadosamente diseñadas de modo MVC pueden inyectar correctamente a su modelo sin tener que escribir algo como

vm.BA.StatesTraveledTo = statesCheckBoxes.Split(',').ToList<string>(); 

y si usted no quiere hacer tal cosa cheque este google search

2

Aquí está el código fuente para ello: http://aspnet.codeplex.com/SourceControl/changeset/view/72551#266451

Es bastante simple,

protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties, IDictionary<string, ValueProviderResult> valueProvider) where TModel : class { 
     if (model == null) { 
      throw new ArgumentNullException("model"); 
     } 
     if (valueProvider == null) { 
      throw new ArgumentNullException("valueProvider"); 
     } 

     Predicate<string> propertyFilter = propertyName => BindAttribute.IsPropertyAllowed(propertyName, includeProperties, excludeProperties); 
    IModelBinder binder = Binders.GetBinder(typeof(TModel)); 

    ModelBindingContext bindingContext = new ModelBindingContext() { 
     Model = model, 
     ModelName = prefix, 
     ModelState = ModelState, 
     ModelType = typeof(TModel), 
     PropertyFilter = propertyFilter, 
     ValueProvider = valueProvider 
    }; 
    binder.BindModel(ControllerContext, bindingContext); 
    return ModelState.IsValid; 
} 

Thi s solo crea un ModelBindingContext y lo vincula. Creo que ya sucede por defecto antes de que se llame su acción. Es raro tener que llamarlo manualmente.

Solo supongo aquí pero es posible que obtengas resultados extraños porque estás haciendo las cosas de forma atípica. La firma de su acción:

public ActionResult Index(UserViewModel vm, FormCollection form) 

toma un UserViewModel AND a FormCollection. Por lo general, las personas hacen una u otra (en realidad, FormCollection es bastante raro hoy en día). Una vez más, me estoy quedando sin memoria aquí, pero supongo que UpdateModel no hace nada porque esos valores ya están vinculados. Si está vacío, tal vez sea porque FormCollection recibe (vincula) todos sus valores submittd y ninguno se queda para que el modelo de vista se enlace.

+0

Gracias. Perdonen mi noobness. ¿Están diciendo que UpdateModel() se ejecuta de manera predeterminada antes de mi acción, por lo que no es necesario ejecutarlo explícitamente desde la acción? – SaltProgrammer

+0

La razón por la que uso FormCollection es porque el archivador de modelo predeterminado (utilizado para ViewModel) no puede enlazar un conjunto de casillas que tengo en la vista con una propiedad List que tengo en un objeto BankAccount dentro del objeto UserViewModel. Mira el código fuente que acabo de agregar a la pregunta. Para mapear correctamente esa propiedad anidada profunda, la tomo directamente de FormCollection. La otra forma de no usar el objeto FormCollection, que yo sepa, es crear un archivador de modelo personalizado, pero no quiero hacerlo más complicado de lo que es, ¿o me falta algo? – SaltProgrammer

+1

Sí, solo crea una clase para los otros valores que quieras con los tipos apropiados para las casillas de verificación. Si puede vincularlo a FormCollection, debería poder vincularlo a un tipo estático. También podrías tomar cosas del objeto Request. –

0

El modelo de actualización se utiliza básicamente para actualizar los valores nuevos en su modelo existente. no necesita asignar valor explícitamente.

+0

Usted dice que no tengo que hacer esto más que ... vm.BA.StatesTraveledTo = statesCheckBoxes.Split (','). ToList (); ??? Si no tengo que hacer eso, ¿cuál es la sintaxis que si solo quisiera usar el método UpdateModel()? – SaltProgrammer