ViewModel
[Validator(typeof(ProdutoCategoriaValidator))]
public class ProdutoCategoriaViewModel
{
[HiddenInput(DisplayValue = false)]
public Guid ID { get; set; }
public IEnumerable<SelectListItem> Tipos { get; set; } // <<<<------- Is not showing in my view
[AdditionalMetadata("data-bind", "event: { change: function(data) { Link(data.Nome()); }}")]
public string Nome { get; set; }
[DataType(DataType.Url)]
[AdditionalMetadata("Prefixo", "Produtos/{tipo-de-produto}#")]
public string Link { get; set; }
public int? Ordem { get; set; }
public ProdutoCategoriaViewModel()
{
ID = Guid.NewGuid();
}
}
Solution
View (_Formulario.cshtml)
@model ProdutoCategoriaViewModel
@using (Html.BeginForm(null, null, FormMethod.Post, new { id="form-produtocategoria", data_bind = "submit: salvar" }))
{
@Html.AntiForgeryToken()
<legend>@Html.MvcSiteMap().SiteMapTitle()</legend>
<fieldset>
@Html.ValidationSummary(false, "Verifique os erros abaixo:")
@Html.EditorForModel()
</fieldset>
<div class="buttons">
@Html.ActionLink("Cancelar", "Index")
<input type="submit" value="SALVAR" />
</div>
}
SelectListItem.cshtml
@model IEnumerable<SelectListItem>
@Html.DropDownListFor(m => m, Model)
<p>Test</p>
Result
Full image: http://i.imgur.com/I7HxA.png
Notes
- I've tried to put the attribute "UIHint" but still nothing is displayed!
Questions
What am I doing wrong?
By default when you use
Html.EditorForModel
don't expect this to recurse down to complex properties such as yourTipos
property which is of typeIEnumerable<SelectListItem>
. Brad Wilson explained this in his blog post (more specifically read the Shallow Dive vs. Deep Dive section towards the end of the post). You will need to write a custom editor template for the Object type if you want this to happen.Another possibility is to specify the template name:
Also bear in mind that your editor template for the
SelectListItem
is wrong because you are binding the DropDownListFor to the model as first argument. Don't forget that the first argument of this helper must be a scalar property that will be used to hold the selected value. You need a string or integer property on your view model for this. The second argument represents the collection.Another important aspect about editor templates is that when you have a property of type
IEnumerable<T>
and an editor template calledT.cshtml
this editor template must be strongly typed to theT
class and notIEnumerable<T>
as you did with yourSelectListItem.cshtml
template. This doesn't apply if you use UIHint or specify the template name as second argument to the EditorFor helper. n this case the template will be typed to the collection.So to recap, you could either implement a custom object editor template as Brad Wilson suggested that will recurse down to complex properties or you could modify your
_Formulario.cshtml
view to specify EditorFor each individual elements.A
@foreach
loop renders something that looks right, but the resulting markup will have the same id for each row's controls. It also will not post the enumerable collection back with the model instance.There are two ways to make this work such that you have a unique id for each item in the collection, and so that the collection is hydrated on postbacks:
1. Use the default editor template rather than a named one
2. Use a
@for
loop, not a@foreach
:This will not work, however:
Nor will this:
For a detailed answer why this is, look at this question: MVC can't override EditorTemplate name when used in EditorFor for child object.