Question

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>  
Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top