Custom HtmlHelper extension method not available in View? - asp.net-mvc

I have translated Jeremiah Clark's CheckBoxList Helper for MVC into my VB.Net project but when I try to use the method in my view I get the error
'CheckBoxList' is not a member of 'System.Web.Mvc.HtmlHelper(Of Attenda.Stargate.Web.UserRolesViewModel)'.
Can anyone tell me where I have gone wrong?
Helper module:
Imports System.Runtime.CompilerServices
Public Module InputExtensions
<Extension()> _
Public Function CheckBoxList(ByVal htmlHelper As HtmlHelper, ByVal name As String, ByVal listInfo As List(Of ListItem)) As String
Return htmlHelper.CheckBoxList(name, listInfo, DirectCast(Nothing, IDictionary(Of String, Object)))
End Function
<Extension()> _
Public Function CheckBoxList(ByVal htmlHelper As HtmlHelper, ByVal name As String, ByVal listInfo As List(Of ListItem), ByVal htmlAttributes As Object) As String
Return htmlHelper.CheckBoxList(name, listInfo, DirectCast(New RouteValueDictionary(htmlAttributes), IDictionary(Of String, Object)))
End Function
<Extension()> _
Public Function CheckBoxList(ByVal htmlHelper As HtmlHelper, ByVal name As String, ByVal listInfo As List(Of ListItem), ByVal htmlAttributes As IDictionary(Of String, Object)) As String
If String.IsNullOrEmpty(name) Then
Throw New ArgumentException("The argument must have a value", "name")
End If
If listInfo Is Nothing Then
Throw New ArgumentNullException("listInfo")
End If
If listInfo.Count < 1 Then
Throw New ArgumentException("The list must contain at least one value", "listInfo")
End If
Dim sb As New StringBuilder()
For Each info As ListItem In listInfo
Dim builder As New TagBuilder("input")
If info.Selected Then
builder.MergeAttribute("checked", "checked")
End If
builder.MergeAttributes(Of String, Object)(htmlAttributes)
builder.MergeAttribute("type", "checkbox")
builder.MergeAttribute("value", info.Value)
builder.MergeAttribute("name", name)
builder.InnerHtml = info.Text
sb.Append(builder.ToString(TagRenderMode.Normal))
sb.Append("<br />")
Next
Return sb.ToString()
End Function
End Module
View source:
<%# Page Title="" Language="VB" MasterPageFile="~/Views/Shared/TwoColumn.Master" Inherits="System.Web.Mvc.ViewPage(Of Attenda.Stargate.Web.UserRolesViewModel)" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Edit User Roles
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Edit Roles for
<%=Html.Encode(Model.User.UserName)%></h2>
<div>
<%=Html.CheckBoxList("Roles", Model.Roles)%>
</div>
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="cphLeftPanel" runat="server">
</asp:Content>

You need to import the namespace containing the custom helper class into your view page. You can do this on the page itself or in the web.config file for all pages. Put the code into a namespace first.
<%# Import Namespace="MyProject.Extensions" %>
or (in the web.config)
<pages>
...
<namespaces>
...
<add namespace="MyProject.Extensions" />
</namespaces>
</pages>

I encountered this problem because I hadn't declared the Module to be Public.
This question also asked here

Related

MVC ViewModel not posting back

I am using Viewmodel, however when I submit the form, I am not getting the values back.
I have a Model Like this...
Public Class ProductSummaryModel
Property productGUID As Integer
Property productName As String
Property productPrice As Double
Property productSku As String
Property categories As String()
Property ShipsWithin As Nullable(Of Integer)
<AllowHtml>
Property productWebDescription As String
Property ImageMainPath As String
End Class
Then I have a ViewModel Like this...
Public Class ProductViewModel
Public ProductSummary As ProductSummaryModel
End Class
Here is my Controller...
Public Function Add() As ActionResult ' Default View To Add Item
Dim prdsummary As ProductViewModel = New ProductViewModel
Return View("Add", prdsummary)
End Function
in my "Add" View I have following...
<tr>
<td>Price: </td>
<td><%=Html.TextBoxFor(Function(f) f.ProductSummary.productPrice)%></td>
</tr>
Problem is, when I submit the FORM, I cant get the POSTED Form Values.
Public Function AddItem(ByVal Model As ProductViewModel) As ActionResult ' Add Item into DB
Dim ajaxMessage As New AjaxFormResponse
Dim prd As ProductSummaryModel = New ProductSummaryModel
Model.ProductSummary = prd
Dim skuID As Integer = 0
msgbox(Model.ProductSummary.categories) ' Empty
End Function
May there is a better way of handling this.
* UPDATE **
I have figured out what the Problem is...When passing Model to ViewModel I had to do this...
Dim Product As ProductViewModel = New ProductViewModel
Dim ProductSummary As New ProductSummaryModel
Product.ProductSummary = ProductSummary
Return View("Add", Product)
Why not use the ProductSummaryModel for binding instead of ProductViewModel. This way you can keep thing simple. Avoid nested bindings if you can.
Also be sure you have using in the view as below, and the HttpPost attr. in the Controller
Product Controller
Public Class ProductController
Inherits Controller
' Main Action
Public Function Main() As ActionResult
Dim prdViewModel As ProductViewModel = New ProductViewModel
prdViewModel.ProductSummary = New ProductSummaryModel
Return View("Main", prdViewModel)
End Function
' Partial Action
Public Function Add() As ActionResult
Dim prdViewModel As ProductViewModel = New ProductViewModel
prdViewModel.ProductSummary = New ProductSummaryModel
Return View("Add", prdViewModel)
End Function
'POST Action from Partial View
<HttpPost()> _
Public Function AddItem(ByVal Model As ProductSummaryModel) As ActionResult ' Add Item into DB
msgbox(Model.productPrice) ' Empty
End Function
End Class
Main View
<%# Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage(Of MvcApplication2.ProductViewModel)" %>
<asp:Content ID="manageTitle" ContentPlaceHolderID="TitleContent" runat="server">
Main Page
</asp:Content>
<asp:Content ID="manageContent" ContentPlaceHolderID="MainContent" runat="server">
<%
Html.RenderPartial("_Add", Model.ProductSummary)
%>
</asp:Content>
Partial View
<%# Page Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of MvcApplication2.ProductSummaryModel)" %>
<asp:Content ID="registerTitle" ContentPlaceHolderID="TitleContent" runat="server">
Register
</asp:Content>
<asp:Content ID="registerContent" ContentPlaceHolderID="MainContent" runat="server">
<% Using Html.BeginForm("AddItem", "Product")%>
<%: Html.AntiForgeryToken() %>
<tr>
<td>Price: </td>
<td><%: Html.TextBoxFor(Function(f) f.productPrice) %></td>
</tr>
<input type="submit" value="Register" />
<% End Using%>
</asp:Content>
UPDATE VIEW MODELS
Public Class ProductSummaryModel
Property productGUID As Integer
Property productName As String
Property productPrice As Double
Property productSku As String
Property categories As String()
Property ShipsWithin As Nullable(Of Integer)
<AllowHtml>
Property productWebDescription As String
Property ImageMainPath As String
End Class
Public Class ProductViewModel
Public ProductSummary As ProductSummaryModel
End Class
I see two problems :
First, you're overriding posted values when you do this :
Dim prd As ProductSummaryModel = New ProductSummaryModel
Model.ProductSummary = prd
The ProductSummary property in the model coming from your view is lost and you only get default values when you read its properties.
Also, you don't show how you set categories values in your view. Are you allowing user inputs or some other operation for this property ?

asp.net mvc view strongly typed with PagedList(of product) vb.net

i have this controller function:
Public Function Index(ByVal id As System.Nullable(Of Integer)) As ActionResult
using db = New DbDataContext()
Dim prod As PagedList(Of product) = db.products.ToPagedList(If(id, 1), 20)
Return View(prod)
End Using
End Function
I have to create a view strongly typed with Dim prod As PagedList(Of product)
<%# Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(PagedList(Of product))" %>
Where is my mistake?
Try changing your page definition:
<%# Page
Title=""
Language="VB"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage(Of Webdiyer.WebControls.Mvc.PagedList(Of Paging.product))" %>
For starters, your Page Inherit looks a little off. Here's one of mine.
Inherits="System.Web.Mvc.ViewPage(Of MyProject.Domain.User)"
Where Domain.User is a class created by LINQ in my DBML.
Then in my controller I have
Function Details(ByVal id As Integer) As ActionResult
Dim user As Domain.User = UserService.GetUserByID(id)
user.LastSeen = (From am In user.ActivityLogs
Select am.ActivityDate
Order By ActivityDate Descending).FirstOrDefault
If Not user Is Nothing Then
Return View(user)
Else
Response.StatusCode = CInt(HttpStatusCode.NotFound)
Return RedirectToAction("NotFound", "Error")
End If
End Function

Searching A Parts Table Using ASP.net MVC and ADO.net Entity Data Model gives Error Object Reference not Set to Instance of Object

Good Morning All,
I am developing a new ASP.net MVC web application. Part of it's functionality is to search the Parts List on the SQL Server database. I have created a ADO.net Entity Data Model as part of the solution and named it PartList. I'm using master pages and want the search control rendered on it. As such, I've created PartsForm.ascx in the Shared directory as:
<%# Control Language="VB" Inherits="System.Web.Mvc.ViewUserControl(Of DielToolMVC.PartList)" %>
<%=Html.ValidationSummary("Please correct the errors and try again")%>
<% Using (Html.BeginForm())%>
<fieldset>
<p>
<label for="Parts">Please enter a part description or NSN.</label>
<%=Html.DropDownList("PARTNAME",Model.PARTNAME )%>
<%=Html.DropDownList("NSN", Model.NSN)%>
<%=Html.ValidationMessage("Part Name or NSN", "*")%>
</p>
<p>
<input type="submit" value="Search" />
</p>
</fieldset>
<% End Using%>
I also created a PartsController which serves 2 purposes: 1) to render the entire parts list on the Parts page and 2) to search the parts list and return results to the PartsForm.ascx. Here's the code for PartsController:
Public Class PartsController
Inherits System.Web.Mvc.Controller
Private _entities As New Diel_inventoryEntities()
'
' GET: /Parts/
Function Index() As ActionResult
Return View(_entities.PartList.ToList())
End Function
'
' GET: /Parts/Details/5
Function Details(ByVal id As Integer) As ActionResult
Return View()
End Function
'
' GET: /Parts/Create
Function Create() As ActionResult
Return View()
End Function
'
' POST: /Parts/Create
<AcceptVerbs(HttpVerbs.Post)> _
Function Create(ByVal collection As FormCollection) As ActionResult
Try
' TODO: Add insert logic here
Return RedirectToAction("Index")
Catch
Return View()
End Try
End Function
'
' GET: /Parts/Edit/5
Function Edit(ByVal id As Integer) As ActionResult
Return View()
End Function
'
' POST: /Parts/Edit/5
<AcceptVerbs(HttpVerbs.Post)> _
Function Edit(ByVal id As Integer, ByVal collection As FormCollection) As ActionResult
Try
' TODO: Add update logic here
Return RedirectToAction("Index")
Catch
Return View()
End Try
End Function
Function Search(ByVal id As String, ByVal SearchType As String) As ActionResult
If SearchType = "description" Then
Dim SearchResult = From p In _entities.PartList _
Where p.PARTNAME = id _
Select p
Return View(SearchResult)
End If
If SearchType = "NSN" Then
Dim SearchResult = From p In _entities.PartList _
Where p.NSN = id _
Select p
Return View(SearchResult)
End If
Return View("UnknownType")
End Function
End Class
Intended search control functionality: Receive input search string and conduct search on either PartName or NSN depending on which dropdownlist selection is made. I would like to output the search results to a separate page. Can anyone provide me with some help and guidance as to how to resolve this issue and create the intended functionality?
Thanks,
Sid
Clarification: I'm not understanding why I receive the error message Object Reference not Set to Instance of Object on the PartsForm.ascx file. Besides the ADO.net Entity Data Model (edmx file), do I need to create a class to define each of the fields in my model? I've seen some of that done in tutorials, but thought that the edmx file took care of that? Is that why this error message is being thrown?
Relevant Code:
<%# Control Language="VB" Inherits="System.Web.Mvc.ViewUserControl(Of DielToolMVC.PartList)" %>
<%=Html.ValidationSummary("Please correct the errors and try again")%>
<% Using (Html.BeginForm("Search", "PartsController"))%>
<fieldset>
<p>
<label for="Parts">Please enter a part description or NSN.</label>
<%=Html.TextBox("searchtext") %>
<%=Html.DropDownList("PARTNAME",Model.PARTNAME )%>
<%=Html.DropDownList("NSN", Model.NSN)%>
<%=Html.ValidationMessage("Part Name or NSN", "*")%>
</p>
<p>
<input type="submit" value="Search" />
</p>
</fieldset>
<% End Using%>
Snippet from PartsController:
Function Search(ByVal id As String, ByVal SearchType As String) As ActionResult
If SearchType = "PARTNAME" Then
Dim SearchResult = From p In _entities.PartList _
Where p.PARTNAME = id _
Select p
Return View(SearchResult)
End If
If SearchType = "NSN" Then
Dim SearchResult = From p In _entities.PartList _
Where p.NSN = id _
Select p
Return View(SearchResult)
End If
Return View("UnknownType")
End Function
Function Result(ByVal id As String, ByVal SearchResult As String) As ActionResult
Return View("SearchResult")
End Function
After modifying PartsController and PartsForm.ascx as displayed above, the error message still persists.
Still fairly vague but here is what I'm seeing.
The page is submitting to itself. not a problem but when you return from your Search controller you are not also returning the PARTNAME or NSN objects.
That may be because you left that out of your question.
If not then create another class which has your search result, PARTNAME and NSN objects and return that to the page.
The use Model.PARTNAME ect and for your products Model.Products or something like that.
If this is wrong then please provide more relevant code or a small snippet of code that fails.
EDIT
Sorry you should return SearchType in your new class back to your view not like I said NSN and PARTNAME

How to bind an Html.DropDownList without ViewData (Strongly-Typed View)

I can't seem to find a good blog post that shows how to bind a model to a view without the magic strings "ViewData" (using a strongly-typed view is the approach I'm trying to take)
Does anyone know what I need to alter in the below to bind this directly to my model?
View
<%# Page Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of IEnumerable (Of MvcApplication1.Category))" %>
<asp:Content ID="aboutContent" ContentPlaceHolderID="MainContent" runat="server">
<%=Html.DropDownList("CategoryList")%>
</asp:Content>
Controller
Function Index() As ActionResult
Dim list As New List(Of Category)
list.Add(New Category With {.CategoryID = 1, .CategoryName = "Test1"})
list.Add(New Category With {.CategoryID = 2, .CategoryName = "Test2"})
Return View()
End Function
EDIT
The final solution in VB is shown below, thanks for the big response!
Controller
Function Index() As ActionResult
Dim id As Integer = 1
Dim ProductObject As Product = mProductService.GetProductById(id)
Return View(ProductObject)
End Function
View
<%=Html.DropDownList("Category", New SelectList(Model.Categories, "CategoryID", "CategoryName"))%>
Product Class (w/ a IEnumeralbe property for the categories)
Public Class Product
Public Sub New()
End Sub
Private mProductID As Integer
Public Property ProductID() As Integer
Get
Return mProductID
End Get
Set(ByVal value As Integer)
mProductID = value
End Set
End Property
ReadOnly Property Categories() As IEnumerable(Of Category)
Get
Dim list As New List(Of Category)
list.Add(New Category With {.CategoryID = 1, .CategoryName = "Test1"})
list.Add(New Category With {.CategoryID = 2, .CategoryName = "Test2"})
Return list
End Get
End Property
End Class
The dropdown list helper takes an IEnumerable<SelectListItem>, not an IEnumerable<Category>. Typically what you do is have your page have a particular model. The model includes a property for the selected value from the dropdown, not the collection. You supply the collection to select from via ViewData. You could have a view-only model that includes both the properties and the collection(s) to select from, but that might mean a proliferation of classes. There's some debate as to whether proliferating classes or magic strings are worse design.
My take on your code would be something like:
<%# Page Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of Foo)" %>
<asp:Content ID="aboutContent" ContentPlaceHolderID="MainContent" runat="server">
<%=Html.DropDownList("Category", ViewData("CategoryList"))%>
</asp:Content>
Function Index() As ActionResult
Dim list As New List(Of SelectListItem)
list.Add(New SelectListItem With {.Value = 1, .Text = "Test1"})
list.Add(New SelectListItem With {.Value = 2, .Text = "Test2"})
ViewData("CategoryList") = list
Return View()
End Function
where Foo is a class that contains a property Category of type int.
If you wanted to do a strongly-typed view, then have Foo have a property Categories of type SelectListItem, then change:
<%=Html.DropDownList("Category", ViewData("CategoryList"))%>
to
<%=Html.DropDownList("Category", Foo.Categories )%>
and
ViewData("CategoryList") = list
Return View()
to
Dim foo as New Foo
foo.Categories = list
Return View(foo)
You could create your own helper method overload for Html.DropDownList that would directly map the model to the DropDownList helper.
That being said, you should really ask your self how much domain specific logic your view should contain. ViewData helps to separate your model and domain logic from your view.
Example:
I know this is not an "overload" because felt that since this will still need a name, you would want another method that just takes a string for the name of the drop down but automatically binds the model to the control (assuming it is an IEnumerable). This is an example of the HtmlHelper extension method.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
namespace MvcApplication3.Helpers
{
public static class ViewHelpers
{
public static string ModelDropDownList(this HtmlHelper htmlHelper, string name)
{
var model = htmlHelper.ViewData.Model as IEnumerable<SelectListItem>;
if(model == null)
return string.Empty;
return htmlHelper.DropDownList(name, model);
}
}
}
Here is how you would call this in your view
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<SelectListItem>>" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<%= Html.ModelDropDownList("Test") %>
</asp:Content>
If you want to go the Strongly Typed method, there is a SelectList object to which you can pass an IEnumerable. You have to specify the Text Field and Value Field properties of T but this SelectList object can be allocated directly to the Html.DropDownList helper:
c#
IList<Category> categories = new IList<Category>()
{
new Category() { ID = 1, Name = "Category 1" },
new Category { ID = 2, Name = "Category 2" }
};
SelectList categoryDropDown = new SelectList(categories, "ID", "Name");
ViewData["categoryDropDown"] = categoryDropDown;
then do:
c#
<%=Html.DropDownList("CategoryID", ViewData("categoryDropDown"))%>
That way you can pass in an IList of categories from anywhere (Service layer, controller wide method).

Can you use ASP.NET MVC UpdateModel() with complex Model Object containing List<T>?

I've seen articles and blog posts indicating what I am attempting to do should be supported; however, I have been unable to get it working so hopefully someone can confirm that it does/does not work and/or tell me what I am doing wrong.
I have a "complex" model (Invoice containing a List of InvoiceItem) that I am attempting to bind to and I would only like to update certain attributes and certain items/indexes on the List objects). I believe my issue is primarily with whether or not the include/exclude works for List data. I am attempting to use UpdateModel() with its includeProperties, like so:
Public Function Edit(ByVal id As String, ByVal values As FormCollection)
Dim invoice As Invoice = _getInvoice(id)
UpdateModel(invoice, "", New String() {"InvoiceDate", "CustomerName", "Items[0].Price"})
'Do some stuff...
End Function
All of my code is below...
I have the following model:
Public Class Invoice
Private _invoiceNumber As String
Private _invoiceDate As DateTime
Private _customerName As String
Private _items As List(Of InvoiceItem)
Public Property InvoiceNumber() As String
Get
Return _invoiceNumber
End Get
Set(ByVal value As String)
_invoiceNumber = value
End Set
End Property
Public Property InvoiceDate() As DateTime
Get
Return _invoiceDate
End Get
Set(ByVal value As DateTime)
_invoiceDate = value
End Set
End Property
Public Property CustomerName() As String
Get
Return _customerName
End Get
Set(ByVal value As String)
_customerName = value
End Set
End Property
Public Property Items() As List(Of InvoiceItem)
Get
Return _items
End Get
Set(ByVal value As List(Of InvoiceItem))
_items = value
End Set
End Property
End Class
Public Class InvoiceItem
Private _itemNumber As Integer
Private _description As String
Private _price As Decimal
Public Property ItemNumber() As Integer
Get
Return _itemNumber
End Get
Set(ByVal value As Integer)
_itemNumber = value
End Set
End Property
Public Property Description() As String
Get
Return _description
End Get
Set(ByVal value As String)
_description = value
End Set
End Property
Public Property Price() As Decimal
Get
Return _price
End Get
Set(ByVal value As Decimal)
_price = value
End Set
End Property
End Class
I have the following View:
<%# Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage(Of MvcApplication2.Invoice)" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<title>Edit</title>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Edit</h2>
<%=Html.ValidationSummary()%>
<% Using Html.BeginForm() %>
<fieldset>
<legend>Fields</legend>
<p>
<label for="InvoiceNumber">InvoiceNumber:</label>
<%= Html.TextBox("InvoiceNumber") %>
<%= Html.ValidationMessage("InvoiceNumber", "*") %>
</p>
<p>
<label for="InvoiceDate">InvoiceDate:</label>
<%= Html.TextBox("InvoiceDate") %>
<%= Html.ValidationMessage("InvoiceDate", "*") %>
</p>
<p>
<label for="CustomerName">CustomerName:</label>
<%= Html.TextBox("CustomerName") %>
<%= Html.ValidationMessage("CustomerName", "*") %>
</p>
<%For x As Integer = 0 To ViewData.Model.Items.Count - 1%>
<p>
<label for="Item<%=ViewData.Model.Items(x).ItemNumber %>">Item <%=ViewData.Model.Items(x).ItemNumber%>:</label>
<%=Html.Hidden("Items.Index", x)%>
<%=Html.TextBox(String.Format("Items[{0}].Description", x), ViewData.Model.Items(x).Description)%>
<%=Html.ValidationMessage("Description", "*")%>
<%=Html.TextBox(String.Format("Items[{0}].Price", x), ViewData.Model.Items(x).Price)%>
<%=Html.ValidationMessage("Price", "*")%>
</p>
<%Next x%>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% End Using %>
</asp:Content>
And here is my Controller:
Public Class InvoicingController
Inherits System.Web.Mvc.Controller
Private Function _getInvoice(ByVal id As String) As Invoice
Dim invoice As New Invoice
invoice.InvoiceNumber = id
invoice.CustomerName = "John Doe"
invoice.InvoiceDate = DateTime.Now
invoice.Items = New List(Of InvoiceItem)
For x As Integer = 1 To 5
Dim item As InvoiceItem = New InvoiceItem
item.ItemNumber = x
item.Description = String.Format("Item {0}", x)
item.Price = 100 + x
invoice.Items.Add(item)
Next
Return invoice
End Function
<AcceptVerbs(HttpVerbs.Post)> _
Function Edit(ByVal id As String) As ActionResult
Dim invoice As Invoice = _getInvoice(id)
Return View(invoice)
End Function
'UpdateModel(invoice, "", New String() {"InvoiceDate", "CustomerName", "Items"}) 'NOTE: THis line appears to update any InvoiceItem attributes that are supplied
UpdateModel(invoice, "", New String() {"InvoiceDate", "CustomerName", "Items[0].Price"}) 'This line does not allow the first item's Price to be updated.
Return View()
End Function
End Class
Thanks in advance!
In your form viewmodel, don't declare properties for fields that you don't want MVC to bind/update.
The MVC binder binds only properties with getter/setter.
Just declare "read only" properties as simple fields.
You can also try adding the [BindNever] attribute on these fields.

Resources