2012-07-14 15 views
11

Abbiamo cercato di far funzionare il modello di editor con una proprietà dinamica, inutilmente. Forse uno di voi può aiutarci.Asp.Net MVC 3 Editor per proprietà dinamiche

Qui è più o meno la nostra classe:

public class Criterion 
{ 
    ... 
    public string Text { get; set; } 
    public dynamic Value { get; set; } 
    public Type Type { get; set; } 
    ... 
} 

nostro punto di vista rasoio ottiene un modello containg un elenco di sezioni che ognuno di essi contiene un elenco di criteri in esso. (Riceviamo queste informazioni in fase di esecuzione.) Tutti questi criteri devono essere visualizzati in modalità di modifica - per quanto riguarda il loro tipo effettivo: (estratto)

@for (int i = 0; i < model.Sections.Count(); i++) 
{ 
    for (int j = 0; j < model.Sections[i].Criteria.Count(); j++) 
    { 
     var criterion = model.Sections[i].Criteria[j]; 
     var type = criterion.Type.Name; 
     var name = "Sections[" + i + "].Criteria[" + j + "].Value"; 
     var criterionDisplayName = criterion.Text; 
     <label for="[email protected](i)[email protected](j)__Value">@criterionDisplayName</label> 
     @Html.Editor(name, type) 
    } 
} 

Ciò mostra per esempio una casella di controllo in modo corretto, ma non usa il valore per impostare correttamente lo stato della casella di controllo (controllato se il criterio.Valore è true). Lo stesso vale per altri tipi, come ints. (Compilare il modulo correttamente dopo una richiesta POST, ma perché MVC utilizza un modello temporaneo per ricreare l'input dell'utente.)

Tanto quanto abbiamo provato e ricercato: è persino possibile utilizzare l'Editor modello con proprietà di tipo dynamic? Se sì, come possiamo farlo funzionare? (Non vorremmo discernere in base al tipo possibile. Vorremmo che il framework MVC utilizzi il modello di editor corretto in base al tipo effettivo.)

risposta

15

Le dinamiche non si adattano bene al disegno di legge con ASP.NET MVC. Mi ricordano di ViewBag e odio lo ViewBag dai tessuti molto profondi del mio corpo. Quindi vorrei adottare un approccio diverso.

Prendiamo ad esempio il seguente modello:

public class Criterion 
{ 
    public string Text { get; set; } 
    public object Value { get; set; } 
} 

valore potrebbe essere qualsiasi tipo che si desidera gestire.

Ora si potrebbe avere un controller che popola questo modello:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     var model = new[] 
     { 
      new Criterion { Text = "some integer", Value = 2 }, 
      new Criterion { Text = "some boolean", Value = true }, 
      new Criterion { Text = "some string", Value = "foo" }, 
     }; 
     return View(model); 
    } 
} 

e quindi una corrispondente vista:

@model IList<Criterion> 

@using (Html.BeginForm()) 
{ 
    for (int i = 0; i < Model.Count; i++) 
    { 
     <div> 
      @Html.LabelFor(x => x[i], Model[i].Text) 
      @Html.EditorFor(x => x[i].Value, "Criterion_" + Model[i].Value.GetType().Name) 
     </div> 
    } 

    <button type="submit">OK</button> 
} 

Ora, per ogni tipo che si desidera gestire si potrebbe definire un editor corrispondente modello:

~/Views/Shared/EditorTemplates/Criterion_String.cshtml:

@model string 
@Html.TextBoxFor(x => x) 

~/Views/Shared/EditorTemplates/Criterion_Boolean.cshtml:

@model bool 
@Html.CheckBoxFor(x => x) 

~/Views/Shared/EditorTemplates/Criterion_Int32.cshtml:

@model int 
@{ 
    var items = Enumerable 
     .Range(1, 5) 
     .Select(x => new SelectListItem 
     { 
      Value = x.ToString(), 
      Text = "item " + x 
     }); 
} 

@Html.DropDownListFor(x => x, new SelectList(items, "Value", "Text", Model)) 

Ovviamente visualizza questo modello nella vista è solo il primo passo. Suppongo che vorrete ottenere i valori che l'utente ha reinserito nell'azione del controller POST per qualche elaborazione. In questo caso sono necessari alcuni piccoli adattamenti. Dobbiamo aggiungere un raccoglitore modello personalizzato che sarà in grado di creare un'istanza del tipo corretto in fase di esecuzione e includere il tipo concreto come campo nascosto per ogni riga. Ho già mostrato un esempio in this post. Notate anche in questo esempio che ho usato una classe base invece di lavorare direttamente con il tipo object.

+0

Funziona con visualizzazione fortemente digitata.Ho provato a cambiare Index-View per non usare la vista fortemente tipizzata: cancellato '@model IList ' e usato il modello '@ {var model = (IList ); } '. Quindi provo '@ Html.Editor (" model ["+ i +"] .Value "," Criterion_ "+ model [i] .Value.GetType(). Name)', ma mi dà un errore _Il modello l'elemento passato nel dizionario è nullo, ma questo dizionario richiede un elemento del modello non null di tipo 'System.Int32' ._ Che cosa sto facendo male? Il debugging mi dice che GetType(). Name è 'Int32' in Index-View. – toni

+0

A proposito: dobbiamo usare la vista non fortemente tipizzata, perché stiamo usando un framework di terze parti (ContentShape di Orchard). – toni

+0

Abbiamo finito per usare l'approccio Darins come sopra con 'object'. Dovevamo solo trasmettere il ViewModel dinamico e passarlo a un modello di editor fortemente tipizzato. Grazie, Darin, per il prezioso contributo. – toni