2010-01-29 14 views
18

que estoy trabajando con ASP.NET MVC2 RC y no puedo encontrar la manera de obtener el asistente de HTML, TextBoxfor trabajar con un modelo de vista patrón. Cuando se utiliza en una página de edición, los datos no se guardan cuando se llama a UpdateModel() en el controlador. He tomado los siguientes ejemplos de código de la aplicación NerdDinner.utilizando el patrón MVC modelo de vista con 2 inflexible de tipos HTML Ayudantes

Edit.aspx

<%@ Language="C#" Inherits="System.Web.Mvc.ViewUserControl<NerdDinner.Models.DinnerFormViewModel>" %> 
... 
<p> 
    // This works when saving in controller (MVC 1) 
    <label for="Title">Dinner Title:</label> 
    <%= Html.TextBox("Title", Model.Dinner.Title) %> 
    <%= Html.ValidationMessage("Title", "*") %> 
</p> 
<p> 
    // This does not work when saving in the controller (MVC 2) 
    <label for="Title">Dinner Title:</label> 
    <%= Html.TextBoxFor(model => model.Dinner.Title) %> 
    <%= Html.ValidationMessageFor(model=> model.Dinner.Title) %> 
</p> 

DinnerController

// POST: /Dinners/Edit/5 

[HttpPost, Authorize] 
public ActionResult Edit(int id, FormCollection collection) { 

    Dinner dinner = dinnerRepository.GetDinner(id); 

    if (!dinner.IsHostedBy(User.Identity.Name)) 
     return View("InvalidOwner"); 

    try { 
     UpdateModel(dinner); 

     dinnerRepository.Save(); 

     return RedirectToAction("Details", new { id=dinner.DinnerID }); 
    } 
    catch { 
     ModelState.AddModelErrors(dinner.GetRuleViolations()); 

     return View(new DinnerFormViewModel(dinner)); 
    } 
} 

Cuando se utiliza el estilo original de ayudante (Http.TextBox) el (cena) llamada UpdateModel funciona como se esperaba y los nuevos valores se guardan.

Cuando se utiliza el nuevo (MVC2) estilo de ayuda (Http.TextBoxFor), la llamada UpdateModel (cena) no actualiza los valores. Sí, los valores actuales se cargan en la página de edición en carga.

¿Hay alguna otra cosa que deba agregar al código del controlador para que funcione? El nuevo helper funciona bien si solo estoy usando un modelo y no un patrón de ViewModel.

Gracias.

+0

Hola, tengo el mismo problema en crear acción. Puede echar un vistazo http://stackoverflow.com/questions/2494940/custom-viewmodel-with-mvc-2-strongly-typed-html-helpers-return-null-object-on-cre –

Respuesta

19

El problema aquí es que su formulario de edición utiliza asistentes fuertemente tipados contra un tipo DinnerFormViewModel, pero está llamando a UpdateModel en un tipo de cena.

Cuando utiliza los ayudantes fuertemente tipados contra el tipo, los ayudantes crean campos de formulario suponiendo que ese es el tipo en el que está publicando. Cuando los tipos no coinciden, hay un problema.

Sin embargo, esto es muy fácil de solucionar. Puede proporcionar un prefijo a UpdateModel que indique que no estaba tratando de editar todo el modelo, que estaba tratando de editar una propiedad del modelo, en este caso, una cena.

UpdateModel(dinner, "Dinner"); 

El otro enfoque es llamar a UpdateModel en el ViewModel real.

var viewModel = new DinnerFormViewModel(); 
viewModel.Dinner = repository.GetDinner(id); 
UpdateModel(viewModel); 

Creo que el primer enfoque es mucho mejor.

+1

No hay nada mejor que obtener su respuesta del PM de un proyecto. Gracias Phil, funcionó muy bien. Usé tu primer ejemplo, que fue simple y directo como esperaba. – Brettski

+0

Estoy siguiendo el mismo ejemplo, pero tengo una excepción al actualizar el modelo: http://stackoverflow.com/questions/2377065/how-to-update-using-mvc2-rc2 – Picflight

+0

Hola Phil, tengo el mismo problema con la acción Crear . Estoy usando un modelo de vista personalizado para el formulario de creación. Cuando intento crear un objeto, no se enlaza desde el formulario. Así que eché un vistazo a la fuente y encontré ese "Categoría.Título" en lugar de "Título". Cómo puedo arreglarlo. Gracias –

1

No estoy 100% seguro, pero parece que el helper fuertemente tipeado crea ids/nombres "Dinner.Title" en lugar de solo "Title" y por lo tanto - UpdateModel no puede enlazarlo.

Desafortunadamente, no he usado el método UpdateModel, así que no sé la solución.

¿Podría agregar html que se muestra en ambos enfoques?


jugando con reflector ATM.

Esto es lo que encontré:

protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties, IValueProvider valueProvider) where TModel: class 
{ 
    if (model == null) 
    { 
     throw new ArgumentNullException("model"); 
    } 
    if (valueProvider == null) 
    { 
     throw new ArgumentNullException("valueProvider"); 
    } 
    Predicate<string> predicate = delegate (string propertyName) { 
     return BindAttribute.IsPropertyAllowed(propertyName, base.includeProperties, base.excludeProperties); 
    }; 
    IModelBinder binder = this.Binders.GetBinder(typeof(TModel)); 
    ModelBindingContext context2 = new ModelBindingContext(); 
    context2.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(delegate { 
     return base.model; 
    }, typeof(TModel)); 
    context2.ModelName = prefix; 
    context2.ModelState = this.ModelState; 
    context2.PropertyFilter = predicate; 
    context2.ValueProvider = valueProvider; 
    ModelBindingContext bindingContext = context2; 
    binder.BindModel(base.ControllerContext, bindingContext); 
    return this.ModelState.IsValid; 
} 

Parámetros
- El modelo de instancia de modelo para actualizar.
- prefijo El prefijo que se utiliza al buscar valores en el proveedor de valores.


Por lo tanto - se puede tratar de utilizar UpdateModel<T>(T model, string prefix) sobrecarga y pasar "cena" o "Cena". como argumento de prefijo.

+0

Gracias, eso parece hacer el truco. El problema que estoy teniendo es por qué agregar los ayudantes fuertemente tipados al andamio si necesitas saltar a través de un aro para usarlos. Me falta algo aquí. – Brettski

+0

@Brettski También he tenido algunas dificultades con ellos (http://stackoverflow.com/questions/2093216/asp-net-mvc2-strongly -typed-htmlhelper- indexes). No te estás perdiendo nada, simplemente no están lo suficientemente maduros, eso es todo. Al menos, así es como lo veo. –

0

Una manera más sencilla es utilizar el prefijo como el nombre del parámetro, sólo lo hacen de esta manera:

public ActionResult Edit(Dinner Dinner, int DinnerID) 
{ 
    ... 
} 
1

Quizás una manera más sencilla de poner esto es como sigue. Si está cortando y pegando el código de la descarga de wrox para el tutorial de NerDDinner, encontrará que hay algunos errores. Usando una sugerencia de arriba, modifiqué el ejemplo de 1-53.txt para hacer que esto funcione. El cambio sigue:

// 
    // POST: /Dinners/Edit/2 
    [HttpPost] 
    public ActionResult Edit(int id, FormCollection formValues) 
    { 
    // Retrieve existing dinner 
    Dinner dinner = dinnerRepository.GetDinner(id); 
    DinnerFormViewModel viewModel = new DinnerFormViewModel(dinner); 

    if (TryUpdateModel(viewModel)) 
    { 
    // Persist changes back to database 
    dinnerRepository.Save(); 
    // Perform HTTP redirect to details page for the saved Dinner 
    return RedirectToAction("Details", new { id = dinner.DinnerID }); 
    } 
    else 
    { 
    return View(viewModel); 
    } 
    } 
2

En la página 90 en el "Wrox Profesional ASP.NET MVC 2" libro de código se muestra como:

if (TryUpdateModel(dinner)) { 
    dinnerRepository.Save(); 

    redirectToAction("Details", new { id=dinner.DinnerID }); 

pero debería leer:

if (TryUpdateModel(dinner, "Dinner")) { 
    dinnerRepository.Save(); 

    redirectToAction("Details", new { id=dinner.DinnerID }); 

Esta sobrecarga de método intentará actualizar el modelo especificado [Cena], en lugar del predeterminado [Modelo de vista], utilizando los valores fr om el proveedor de valor del controlador. Básicamente, todo lo que hace es agregar un prefijo a todos sus valores cuando los busca en el proveedor.

Por lo tanto, cuando el Modelo esté buscando actualizar su propiedad de título, buscará Dinner.Title, en lugar de solo Title en el proveedor de valores del controlador.

Al depurar, échele un vistazo al método Edit ActionResult e inspeccione el parámetro de entrada FormCollection. Al cavar en su gama de entrada, encontrará Teclas que todos comienzan con el prefijo de la propiedad objeto al que hizo referencia en su opinión, en su caso, la vista de edición, así:

<%: Html.TextBoxFor(model => model.Dinner.Title, new {size=50, @class="prettyForm" })%> 
Cuestiones relacionadas