2015-04-22 10 views
16

Ho un ViewModel che ha un oggetto complesso come uno dei suoi membri. L'oggetto complesso ha 4 proprietà (tutte le stringhe). Sto cercando di creare una vista parziale riutilizzabile in cui posso passare l'oggetto complesso e fargli generare l'html con helper html per le sue proprietà. Funziona tutto alla grande. Tuttavia, quando invio il modulo, il raccoglitore modello non sta mappando i valori sul membro ViewModel in modo da non ottenere nulla sul lato server. Come posso leggere i valori che un utente digita negli helper html per l'oggetto complesso.acquisizione dei valori da un oggetto complesso nidificato passato a una vista parziale

ViewModel

public class MyViewModel 
{ 
    public string SomeProperty { get; set; } 
    public MyComplexModel ComplexModel { get; set; } 
} 

MyComplexModel

public class MyComplexModel 
{ 
    public int id { get; set; } 
    public string Name { get; set; } 
    public string Address { get; set; } 
    .... 
} 

controller

public class MyController : Controller 
{ 
    public ActionResult Index() 
    { 
      MyViewModel model = new MyViewModel(); 
      model.ComplexModel = new MyComplexModel(); 
      model.ComplexModel.id = 15; 
      return View(model); 
    } 

    [HttpPost] 
    public ActionResult Index(MyViewModel model) 
    { 
      // model here never has my nested model populated in the partial view 
      return View(model); 
    } 
} 

View

@using(Html.BeginForm("Index", "MyController", FormMethod.Post)) 
{ 
    .... 
    @Html.Partial("MyPartialView", Model.ComplexModel) 
} 

Vista Parziale

@model my.path.to.namespace.MyComplexModel 
@Html.TextBoxFor(m => m.Name) 
... 

come posso associare questi dati sul modulo di presentazione in modo che il modello principale contiene i dati inseriti nel modulo web dal punto di vista parziale?

grazie

EDIT: "ComplexModel" Ho capito che ho bisogno di anteporre a tutti i nomi del mio controllo nella vista parziale (caselle di testo) in modo che si associ all'oggetto nidificato, ma non posso passare il tipo ViewModel alla vista parziale per ottenere quel livello in più perché deve essere generico per accettare diversi ViewModel tipi. Potrei semplicemente riscrivere l'attributo name con javascript, ma mi sembra troppo ghetto. In quale altro modo posso fare questo?

EDIT 2: Posso impostare staticamente l'attributo name con new {Name = "ComplexModel.Name"} quindi penso di essere in affari a meno che qualcuno non abbia un metodo migliore?

risposta

21

È possibile passare il prefisso al parziale utilizzando

@Html.Partial("MyPartialView", Model.ComplexModel, 
    new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "ComplexModel" }}) 

che Perpend il prefisso a voi controlli attributo name in modo che <input name="Name" ../> diventerà <input name="ComplexModel.Name" ../> e corretto legarsi a typeof MyViewModel sul palo

Modifica

Per semplificare l'operazione, è possibile racchiuderlo in un helper html

public static MvcHtmlString PartialFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, string partialViewName) 
{ 
    string name = ExpressionHelper.GetExpressionText(expression); 
    object model = ModelMetadata.FromLambdaExpression(expression, helper.ViewData).Model; 
    var viewData = new ViewDataDictionary(helper.ViewData) 
    { 
    TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = name } 
    }; 
    return helper.Partial(partialViewName, model, viewData); 
} 

e usarlo come

@Html.PartialFor(m => m.ComplexModel, "MyPartialView") 
+0

questo sembra molto promettente. Ho lasciato l'ufficio per la giornata, ma gli darò una possibilità domani quando tornerò e segnerò come risposta se funziona per me. Grazie. –

+0

questo è perfetto !! grazie mille –

+0

boo ... Non riesco a sospenderlo perché dice che devo avere 15 reputazione. +1 per voi anche se, come appena ottengo i 15 rep :) –

0

È possibile provare a passare ViewModel al parziale.

@model my.path.to.namespace.MyViewModel 
@Html.TextBoxFor(m => m.ComplexModel.Name) 

Modifica

È possibile creare un modello base e spingere il modello complesso in là e passare il modello basato al parziale.

public class MyViewModel :BaseModel 
{ 
    public string SomeProperty { get; set; } 
} 

public class MyViewModel2 :BaseModel 
{ 
    public string SomeProperty2 { get; set; } 
} 

public class BaseModel 
{ 
    public MyComplexModel ComplexModel { get; set; } 
} 
public class MyComplexModel 
{ 
    public int id { get; set; } 
    public string Name { get; set; } 
    ... 
} 

Allora la vostra parziale sarà come di seguito:

@model my.path.to.namespace.BaseModel 
@Html.TextBoxFor(m => m.ComplexModel.Name) 

Se questa non è una soluzione accettabile, potrebbe essere necessario pensare in termini di priorità assoluta del modello legante. Puoi leggere quello here.

+0

io non posso farlo perché ha bisogno di essere generico. Ci saranno diversi ViewModels principali che hanno il loro tipo che dovrà essere passato in ... Vedi la mia prima modifica nell'OP. –

0

mi sono imbattuto la stessa situazione e con l'aiuto di tali messaggi informativi cambiato il mio codice parziale di avere il prefisso sul generata in elementi di input generati da vista parziale

ho usato Html.partial aiutante dando nome PartialView ed oggetto di ModelType e un'istanza di oggetto ViewDataDictionary con Html campo prefisso al costruttore di Html.partial.

Ciò comporta richiesta GET "xyz URL" di "Vista principale" e il rendering vista parziale all'interno con elementi di input generati con prefisso esempio in precedenza Name = "Title" ora diventa Name = "MySubType.Title" nel rispettivo elemento HTML e lo stesso per il resto degli elementi di input del modulo.

Il problema si è verificato quando richiesta POST è fatta per "xyz url", aspettandosi il modulo che viene compilato viene salvato nella mia base di dati. Ma MVC Modelbinder non ha vincolato i dati del modello POSTed con i valori dei moduli compilati e anche ModelState è stato perso. Anche il modello in viewdata stava arrivando a zero.

Infine, ho provato ad aggiornare i dati del modello in forma postata utilizzando il metodo TryUppdateModel che prende l'istanza del modello e il prefisso html passato in precedenza alla vista parziale e può vedere ora il modello è associato con valori e lo stato del modello è anche presente.

Si prega di farmi sapere se questo approccio va bene o bit diversificato!

Problemi correlati