Can using “@inherits” solve my editor templates IEnumerable headaches?
-
27-06-2021 - |
Pergunta
I think it might be easier to explain by showing some code and explaining as I go along:
Create Product ViewModel:
[UIHint("Prices")]
public IList<CreatePricesViewModel> Prices { get; set; }
With this, I want the ability to use an ajax call to add another set of prices for a different currency to the product.
Create Prices ViewModel:
[DataType(DataType.Currency)]
[DisplayName("Wholesale Price: ")]
public decimal Wholesale { get; set; }
[DataType(DataType.Currency)]
[Required]
[DisplayName("Retail Price: ")]
public decimal Retail { get; set; }
[DataType(DataType.Currency)]
[DisplayName("Discounted Price: ")]
public decimal Discount { get; set; }
In my controller I create a single CreatePricesViewModel and add it to the CreateProductViewModels list of CreatePricesViewModel's so there is at least one available instance to render in the view.
Create Product View:
@model CumbriaMD.Infrastructure.ViewModels.ProductViewModels.CreateProductViewModel
......
<div class="editor-field">
@Html.EditorFor(model => model.Prices)
@Html.ValidationMessageFor(model => model.Prices)
</div>
Prices EditorFor Templates:
This is where I'm struggling really. When I strongly-type to the CreatePricesViewModel I get a complaint because I'm passing in an IEnumerable of type CreatePricesViewModel instead of a single instance - but when I use a foreach loop my id and names are messed up so the model-binding fails? Can using @inherits here help?
@model CumbriaMD.Infrastructure.ViewModels.PriceViewModels.CreatePricesViewModel
<div class="editor-label">
@Html.LabelFor(model => model.Wholesale)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Wholesale)
@Html.ValidationMessageFor(model => model.Wholesale)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Retail)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Retail)
@Html.ValidationMessageFor(model => model.Retail)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Discount)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Discount)
@Html.ValidationMessageFor(model => model.Discount)
</div>
Solução
No, @inherits
cannot solve your headaches.
When using UIHint
, the entire enumerable is passed, so you need to make your template strongly typed to the list:
@model IEnumerable<CumbriaMD.Infrastructure.ViewModels.PriceViewModels.CreatePricesViewModel>
@foreach(var item in Model)
{
@Html.Partial("_SomePrice", item)
}
and then define _SomePrice.cshtml
partial:
@model CumbriaMD.Infrastructure.ViewModels.PriceViewModels.CreatePricesViewModel
<div class="editor-label">
@Html.LabelFor(model => model.Wholesale)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Wholesale)
@Html.ValidationMessageFor(model => model.Wholesale)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Retail)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Retail)
@Html.ValidationMessageFor(model => model.Retail)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Discount)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Discount)
@Html.ValidationMessageFor(model => model.Discount)
</div>
This is not necessary when you don't use the UIHint attribute => the editor template is automatically invoked for each element of the Prices collection. It sucks but it's how it is.