ModelState.IsValid is always returning true.
Code:
user.cs
public class User
{
public int UserID { get; set; }
public string Username { get; set; }
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
}
HomeController.cs
public ActionResult SaveUser(User user)
{
if (ModelState.IsValid)
{
//create DBContext object
using (var dbCtx = new UsersDbEntities())
{
dbCtx.Entry(user).State = EntityState.Modified;
dbCtx.SaveChanges();
}
return View("ShowUser", user);
}
return View("EditUser", user);
}
Register.cshtml
#model TrainingWebsite.Models.User
<div id="myForm">
#using (Html.BeginForm("RegisterUser", "Home", FormMethod.Post))
{
if (#ViewBag.Message != null)
{
<div style="border: 1px solid red">
#ViewBag.Message
</div>
}
<table>
<tr>
<td>#Html.LabelFor(a => a.Username)</td>
<td>#Html.TextBoxFor(a => a.Username, new { id = "id_username" })</td>
<td>#Html.ValidationMessageFor(a => a.Username)</td>
</tr>
<tr>
<td>#Html.LabelFor(a => a.FirstName)</td>
<td>#Html.TextBoxFor(a => a.FirstName, new { id = "id_firstName" })</td>
<td>#Html.ValidationMessageFor(a => a.FirstName)</td>
</tr>
<tr>
<td>#Html.LabelFor(a => a.LastName)</td>
<td>#Html.TextBoxFor(a => a.LastName, new { id = "id_lastName" })</td>
<td>#Html.ValidationMessageFor(a => a.LastName)</td>
</tr>
</table>
ModelState.IsValid is true even though Last Name field is empty yet is a required field
Any help would be appreciated. Thanks in advance
David
Related
I'm trying to make a simple shopping cart app in Asp.Net Core 2.0 MVC. I'm not doing any Ajax-ing. I have three models:
public class Product
{
public int Id { get; set; }
public string Title { get; set; }
public string Info { get; set; }
public decimal Price { get; set; }
}
public class Cart
{
public int Id { get; set; }
public int CartItemId { get; set; }
public int CustomerId { get; set; } // not in use yet
}
public class CartItem
{
public int Id { get; set; }
public int ProductId { get; set; }
public int NumEach { get; set; } // not in use yet
}
From either one of the two views below, I want to update Cart and CartItem, and then get redirected back to the view where I clicked the Add to cart-button:
1) Index-view:
#model IEnumerable<simpleShop.Models.Product>
<table class="table">
<thead>
<tr>
<th>#Html.DisplayNameFor(model => model.Title)</th>
<th>#Html.DisplayNameFor(model => model.Info)</th>
<th>#Html.DisplayNameFor(model => model.Price)</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
<a asp-action="Details" asp-route-id="#item.Id">
#Html.DisplayFor(modelItem => item.Title)
</a>
</td>
<td>#Html.DisplayFor(modelItem => item.Info)</td>
<td>#Html.DisplayFor(modelItem => item.Price)</td>
<td>
<form asp-action="AddToCart">
<button type="submit" value="#item.Id">Add to cart</button>
</form>
</td>
</tr>
}
</tbody>
</table>
2) Details-view:
#model simpleShop.Models.Product
#{
ViewData["Title"] = Html.DisplayFor(model => model.Title);
}
<h2>#Html.DisplayFor(model => model.Title)</h2>
<h4>#Html.DisplayFor(model => model.Info)</h4>
<h1>#Html.DisplayFor(model => model.Price)</h1>
<form asp-action="AddToCart">
<input type="hidden" asp-for="Id" />
<p>
<input type="submit" value="Add to cart" />
</p>
</form>
<div>
<a asp-action="Index">Return to list</a>
</div>
Below is my faulty AddToCart-method in the home controller, which at the moment certainly isn't doing anything to save data to the Cart or CartItem tables. How can I get it to?
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddToCart([Bind("Id")] Product product)
{
if (ModelState.IsValid)
{
_context.Add(product);
await _context.SaveChangesAsync();
if (product.Id > 0) // added to cart via the details-view
{
return RedirectToAction("Details", "Home", product.Id);
}
else // added to cart via the index-view
{
return RedirectToAction(nameof(Index));
}
}
return View(product);
}
for one thing Bind() requires way more than just "id", remember what ever you wanted to bind has to include all properties in question of the object you wanted to pass to new action.
reference comments in line -->>
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddToCart([Bind("Id")] Product product)
{
if (ModelState.IsValid)
{
_context.Add(product); //**BAD this will probably try to
// add product to the product table again.**
// With error to follow about already exists
// exception at the SaveChangesAsync call.
await _context.SaveChangesAsync();
if (product.Id > 0)
{
return RedirectToAction("Details", "Home", product.Id);
}
else // added to cart via the index-view
{
return RedirectToAction(nameof(Index));
}
}
return View(product);
}
My suggestion goes along these lines where you will have ProductId and Qty of the Product (your NumEach)
[HttpPost]
[ValidateAntiForgeryToken]
public asyync Task<IActionResult> AddToCart([Bind("ProductId", "NumEach", "CartId")] CartItem model, string ReturnUrl){
if(ModelState.IsValid){
_context.CartItem.Add(model);
await _context.SaveChangesAsync();
//model.Id greater than 0 indicates a save occurred.
if(model.Id > 0)
return RedirectToAction(ReturnUrl); // forced return for further shopping?
else
return RedirectToAction("Index");
}
//this assumes bad model state with no error unless model is
//annotated accordingly.
return View(model);
}
problem with Cart though is right now you can only store 1 item...
public class Cart{
public Cart(){}
public int Id {get;set;} //cart's integer id
public List<CartItem> CartItems {get;set;} //collection of cartitems
//FK
public int CustomerId {get;set;} //customer's id
//NAV
public Customer CustomerId {get;set;} //customer nav
...
}
public class CartItem{
public CartItem(){}
public int Id {get;set;} //cart item id
public int ProductId {get;set;} //productid
public Product Product {get;set;} //nav property
public int NumEach {get;set;} //quantity of each product
//FK
public int CartId {get;set;} //Foreign Key
//NAV
public Cart Cart {get;set;} //nav property
}
One other thing your index view wouldn't just have the model be a collection of Products it would probably be a viewmdodel that had a collection of products in it but it would also contain the cartid that would have been generated with the visitor. That CartId would follow that visitor until the transaction was completed and you then have an OrderId or it dies once the session is closed.
#model simpleShop.Models.IndexViewModel
<table class="table">
<thead>
<tr>
<th>#Html.DisplayNameFor(model => model.Title)</th>
<th>#Html.DisplayNameFor(model => model.Info)</th>
<th>#Html.DisplayNameFor(model => model.Price)</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Products)
{
<tr>
<td>
<a asp-action="Details" asp-route-id="#item.Id">
#Html.DisplayFor(modelItem => item.Title)
</a>
</td>
<td>#Html.DisplayFor(modelItem => item.Info)</td>
<td>#Html.DisplayFor(modelItem => item.Price)</td>
<td>
<form asp-action="AddToCart">
<input type="Hidden" asp-for="#Model.CartId" />
<button type="submit" value="#item.Id">Add to cart</button>
</form>
</td>
</tr>
}
</tbody>
</table>
public class IndexViewModel
{
public IndexViewModel(){}
public int CartId{get;set;}
public List<Product> Products{get;set;}
}
I think you get the idea from there.
MVC4 How to get the data in partial view when parent view click submit
I create a edit page for user update the data, the parent view show some of book details and partial view is a loop show the status of each book. Also, the parent view have a submit button for update both of partial view and parent view, but when I click the submit only parent view data can update and partial view still not update. The code below:
Model:
public class LibraryInventory
{
public decimal LibraryID { get; set; }
public string Title { get; set; }
public List<LibraryItem> Entities { get; set; }
}
public class LibraryItem
{ public decimal StatusID { get; set; }
public string Location { get; set; }
public decimal BorrowedBy { get; set; }
}
Controller :
public ActionResult EditRecord(string ID)
{
DataTable dt = (DataTable)Session["EditGridData"];
LibraryInventory record = new LibraryInventory(dt.Rows[0]);
dt = LibraryEditBLL.GetEditItems(ID);
if (results.ToList().Count > 0)
{
record.Entities = LibraryItem.ConvertToLibraryEntity(dt).ToList();
}
return View(record);
}
[HttpPost]
public ActionResult EditRecord(string FormButton, LibraryInventory model)
{
switch (FormButton)
{
case "Submit":
if (ModelState.IsValid)
{
LibraryEditBLL.UpdateInventoryLibrary(model);
}
return View("EditRecord",record);
default:
return RedirectToAction("Edit"); //other page not need check
}
View :
#model XXX.Models.LibraryModels.LibraryInventory
#using (Html.BeginForm("EditRecord", "Library", FormMethod.Post, new { enctype = "multipart/form-data" })){
#Html.HiddenFor(m =>m.LibraryID)
<table>
<tr>
<td>#Html.TextBoxFor(m => m.Title)</td>
#for (var i = 0; i < #Model.Entities.Count; i++)
{
#Html.Partial("EditItem", #Model.Entities[i])
}
</tr>
</table>
}
#model XXX.Models.LibraryModels.LibraryItem
<tr>
<td> #Html.DropDownListFor(m => m.StatusID) </td>
<td> #Html.DropDownListFor(m => m.Location)</td>
<td> #Html.DropDownListFor(m => m.BorrowedBy) </td>
</tr>
Try this code for your view. And no need of partialview for this simple scenario.
#model XXX.Models.LibraryModels.LibraryInventory
#using (Html.BeginForm("EditRecord", "Library", FormMethod.Post, new { enctype = "multipart/form-data" })){
#Html.HiddenFor(m =>m.LibraryID)
<table>
<tr>
<td>#Html.TextBoxFor(m => m.Title)</td>
</tr>
#for (var i = 0; i < Model.Entities.Count; i++)
{
<tr>
<td> #Html.DropDownListFor(m => Model.Entities[i].StatusID) </td>
<td> #Html.DropDownListFor(m => Model.Entities[i].Location)</td>
<td> #Html.DropDownListFor(m => Model.Entities[i].BorrowedBy) </td>
</tr>
}
</table>
}
I am having issues with a view model that constantly return null properties after a post. Below is my code (it could be a syntax issue or two calling a class or property the same name as i saw in other posts but i could not see any such issue in code):
VIEW MODEL:
public class ProductItem
{
public int ProductID { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string LongDescription { get; set; }
public int SupplierID { get; set; }
public string Dimensions { get; set; }
public double Price { get; set; }
public bool On_Sale { get; set; }
public double DiscountedPrice { get; set; }
public string Thumbnail { get; set; }
public string LargeImage { get; set; }
public string LargeImage2 { get; set; }
public string LargeImage3 { get; set; }
public string CrossRef { get; set; }
public byte Available { get; set; }
public double Weight { get; set; }
public byte Important { get; set; }
public virtual ICollection<ProductCategory> ProductCategories { get; set; }
// this is required on the page to allow products to be marked for deletion
public bool IsForDelete { get; set; }
}
public class ProductListViewModel
{
public IEnumerable<ProductItem> ProductItems { get; set; }
public IEnumerable<Category> CategoryItems { get; set; }
}
CONTROLLER:
public ActionResult ProductList()
{
var productList = new ProductListViewModel();
productList.ProductItems = productRepository.GetProductsWithDeleteOption().ToList();
productList.CategoryItems = categoryRepository.GetCategories().ToList();
return View(productList);
}
[HttpPost]
public ActionResult ProductList(ProductListViewModel productViewModel, FormCollection formCollection, string submit)
{
if (ModelState.IsValid)
{
// Check for submit action
if (submit == "Change Sort")
{
if (formCollection["Sortby"] == "ProductID")
{
OrderBy(productViewModel, formCollection, "m.ProductID");
}
else if (formCollection["Sortby"] == "Code")
{
OrderBy(productViewModel, formCollection, "m.Code");
}
else if (formCollection["Sortby"] == "Name")
{
OrderBy(productViewModel, formCollection, "m.Name");
}
else if (formCollection["Sortby"] == "Price")
{
OrderBy(productViewModel, formCollection, "m.Price");
}
}
else if (submit == "Delete all selected")
{
}
else if (submit == "Update All")
{
}
else if (submit == "Restrict Display")
{
}
}
return View(productViewModel);
}
VIEW:
#model Admin.Models.ViewModels.ProductListViewModel
#{
ViewBag.Title = "View Products";
}
#using (Html.BeginForm())
{
<h2>Product List as at #DateTime.Now.ToString("dd/MM/yyyy")</h2>
<table>
<tr>
<td>Sort by:</td>
<td>
<select name="Sortby">
<option value="ProductID">ProductID</option>
<option value="Code">Code</option>
<option value="Name">Name</option>
<option value="Price">Price</option>
</select>
</td>
<td>
<input type="radio" name="sortDirection" checked="checked" value="Asc" /> Ascending
<input type="radio" name="sortDirection" value="Desc" /> Descending
</td>
<td>
<input type="submit" name="submit" value="Change Sort" />
</td>
</tr>
<tr>
<td>Display only : (category)</td>
<td>#Html.DropDownList("CategoryID", new SelectList(Model.CategoryItems, "CategoryID", "Name"), "All Categories")</td>
<td colspan="2"><input type="submit" name="submit" value="Restrict Display" /></td>
</tr>
<tr>
<td colspan="4"><br />Total Number of products: #Model.ProductItems.Count()</td>
</tr>
</table>
<table>
<tr>
<th>
Edit
</th>
<th>
Code
</th>
<th>
Name
</th>
<th>
Price
</th>
<th>
On_Sale
</th>
<th>
DiscountedPrice
</th>
<th>
Weight
</th>
<th>
Delete
</th>
<th></th>
</tr>
#for (var i = 0; i < Model.ProductItems.ToList().Count; i++)
{
<tr>
<td>
#Html.HiddenFor(m => m.ProductItems.ToList()[i].ProductID)
#Html.ActionLink(Model.ProductItems.ToList()[i].ProductID.ToString(), "ProductEdit", new { id = Model.ProductItems.ToList()[i].ProductID })
</td>
<td>
#Html.DisplayFor(m => m.ProductItems.ToList()[i].Code)
</td>
<td>
#Html.DisplayFor(m => m.ProductItems.ToList()[i].Name)
</td>
<td>
#Html.EditorFor(m => m.ProductItems.ToList()[i].Price)
</td>
<td>
#Html.CheckBoxFor(m => m.ProductItems.ToList()[i].On_Sale, new { id = "On_Sale_" + Model.ProductItems.ToList()[i].ProductID })
</td>
<td>
#Html.EditorFor(m => m.ProductItems.ToList()[i].DiscountedPrice)
</td>
<td>
#Html.EditorFor(m => m.ProductItems.ToList()[i].Weight)
</td>
<td>
#Html.CheckBoxFor(m => m.ProductItems.ToList()[i].IsForDelete, new { id = Model.ProductItems.ToList()[i].ProductID })
</td>
<td>
#Html.ActionLink("Edit", "ProductEdit", new { id = Model.ProductItems.ToList()[i].ProductID }) |
#Html.ActionLink("Details", "Details", new { id = Model.ProductItems.ToList()[i].ProductID }) |
#Html.ActionLink("Delete", "Delete", new { id = Model.ProductItems.ToList()[i].ProductID })
</td>
</tr>
}
</table>
<p>
<input name="submit" type="submit" value="Delete all selected" />
</p>
<p>
<input name="submit" type="submit" value="Update All" />
</p>
<p>
#Html.ActionLink("Add a new product", "ProductAdd")
</p>
}
In the post action, the productViewModel argument has the ProductItems and CategoryItems properties as null.
Ok, so there are two problems.
I don't understand why you want to post list of the CategoryItems You should only expect the selected category and not the list
The problem with ProductItems is the name generated for <input> tags. Currently, the name being generated is name="[0].Price" whereas it should have been name="ProductItems[0].Price"
I changed the following code
#Html.EditorFor(m => m.ProductItems.ToList()[i].Price)
to
#Html.EditorFor(m => m.ProductItems[i].Price)
and it worked.
Note: I changed IEnumerable<ProductItem> ProductItems to List<ProductItem> ProductItems in ProductListViewModel
Yes it will be null on post back. I have a similar table in one of my projects and this is what I would have done given my situation.
You could change your view model to look like this then you don't have to do so many converting to lists in your view:
public class ProductListViewModel
{
public List<ProductItem> ProductItems { get; set; }
public List<Category> CategoryItems { get; set; }
}
Now in you view it could look something like this (this is just part of it, then rest you can just go and add):
#for (int i = 0; i < Model.ProductItems.Count(); i++)
{
<tr>
<td>
#Html.DisplayFor(m => m.ProductItems[i].Name)
#Html.HiddenFor(m => m.ProductItems[i].Name)
</td>
</tr>
<tr>
<td>
#Html.CheckBoxFor(m => m.ProductItems[i].IsForDelete)
</td>
</tr>
}
Add the code and do some debugging to see how the values are returned on submit
I hope this helps.
Model :
public IEnumerable<Role> Roles { get; set; }
Index :
Roles = securityServiceClient.GetAllRoles()
View :
#foreach (var role in Model.Roles)
{
<tr>
#if (role.Name == "User")
{
<td><input type="checkbox" checked="checked"/></td>
}
else
{
<td><input type="checkbox"/></td>
}
<td>#Html.Label(role.Name)</td>
</tr>
}
[HttpPost]
CreateSomething :
How can I get the selected checkbox(s) from the view?
You must give your checkboxes names:
#if (role.Name == "User")
{
<td><input type="checkbox" checked="checked" name="roles"/></td>
}
else
{
<td><input type="checkbox" name="roles"/></td>
}
and then:
[HttpPost]
public ActionResult Index(IEnumerable<string> roles)
{
...
}
Also you should be using view models, strongly typed views and helpers and not hardcode checkboxes as you did in your veiws.
Here's what I mean:
Model:
public class MyViewModel
{
public RoleViewModel[] Roles { get; set; }
}
public class RoleViewModel
{
public string RoleName { get; set; }
public bool IsSelected { get; set; }
}
and then:
public class HomeController: Controller
{
public ActionResult Index()
{
var roles = securityServiceClient.GetAllRoles().Select(r => new RoleViewModel
{
RoleName = r.Name
});
var model = new MyViewModel
{
Roles = roles
};
return View(model);
}
[HttpPost]
public ActionResult Index(IEnumerable<RolesViewModel> roles)
{
...
}
}
and in the view:
#model MyViewModel
#using (Html.BeginForm())
{
<table>
<thead>
<tr>
<th>role</th>
</tr>
</thead>
<tbody>
#for (var i = 0; i < Model.Roles.Length; i++)
{
<tr>
<td>
#Html.CheckBoxFor(x => x.Roles[i].IsSelected)
#Html.LabelFor(x => x.Roles[i].IsSelected, Model.Roles[i].RoleName)
#Html.HiddenFor(x => x.Roles[i].RoleName)
</td>
</tr>
}
</tbody>
</table>
}
My question isn't so much about displaying the data its about collecting changes to the data.
My specific scenario is the need to allow users to delete multiple items from a list. I don't know if i'm even approaching this in a locgical way.
The List is a collection of Private Messages. My view model has strings for To, From, Subject, and a bool for "Delete".
public class PrivateMessagesModel {
public PrivateMessagesModel()
{
PrivateMessages = new List<PrivateMessageReceivedModel>();
}
public List<PrivateMessageReceivedModel> PrivateMessages;
}
public class PrivateMessageReceivedModel
{
[DataType(DataType.Text)]
[Display(Name = "From")]
public string From { get; set; }
[DataType(DataType.Text)]
[Display(Name = "Subject")]
public string Subject { get; set; }
[DataType(DataType.Text)]
[Display(Name = "Message")]
public string Message { get; set; }
[DataType(DataType.Text)]
[Display(Name = "Date")]
public DateTime DateTimeSent { get; set; }
[DataType(DataType.Text)]
[Display(Name = "Delete")]
public bool Delete { get; set; }
}
The code to display looks like this. And works ok.
#
model ScaleRailsOnline.Models.PrivateMessagesModel
#{
ViewBag.Title = "Private Messages";
}
<div id="content">
<div class="content">
<h2>
Private Messages</h2>
#using (Html.BeginForm())
{ <table>
#for (int i = 0; i < Model.PrivateMessages.Count; i++)
{
<tr>
<td>
#Html.CheckBoxFor(m => m.PrivateMessages[i].Delete)
</td>
<td>
#Html.DisplayTextFor(m => m.PrivateMessages[i].From)
</td>
</tr>
}
</table>
<p>
<input type="submit" value="Delete" />
</p>
}
</div>
</div>
The problem is when I check a couple of the check boxes and hit the delete button, i get nothing back in the model.
Again, im sure i'm not approaching this in the right way. Any help would be appreciated.
You need to have a controller associated to the Html.BeginForm where the form will be posted.
eg
<div id="formid">
#using (Html.BeginForm("Index1", "Home", new AjaxOptions { UpdateTargetId = "formid",OnSuccess ="OnSuccess" }, new { id = "TheForm" }))
{
#for (int i = 0; i < Model.PrivateMessages.Count; i++)
{
#Html.CheckBoxFor(m => m.PrivateMessages[i].Delete)
}
<input type="submit" name="name" value="Submit" />
}
</div>
On Controller
public ActionResult Index1(List<PrivateMessageReceivedModel> mod)
{
//Now in the mod you will get the value of the delete checkbox.
}
You have to create a Controller class for your model. Then create method that return ActionResult type. and then create View of the newly created controller method.
Here is a sample code.
Model Class
namespace Mvc3Application1.Models
{
public class PrivateMessage
{
public string From { get; set; }
public string Subject { get; set; }
public string Message { get; set; }
public DateTime DateTimeSent { get; set; }
public bool Delete { get; set; }
}
public class PrivateMessageRepository
{
public List<PrivateMessage> GetPrivateMessages()
{
List<PrivateMessage> myPrivateMessages=new List<PrivateMessage>();
//add list of messages in the object myPrivateMessages
myPrivateMessages.Add(new PrivateMessage { From = "abc#abc.com", Subject = "Subject 1", Message = "Message 1", DateTimeSent = DateTime.Now, Delete = false });
myPrivateMessages.Add(new PrivateMessage { From = "abc1#abc.com", Subject = "Subject 2", Message = "Message 2", DateTimeSent = DateTime.Now, Delete = false });
myPrivateMessages.Add(new PrivateMessage { From = "abc2#abc.com", Subject = "Subject 3", Message = "Message 3", DateTimeSent = DateTime.Now, Delete = false });
myPrivateMessages.Add(new PrivateMessage { From = "abc3#abc.com", Subject = "Subject 4", Message = "Message 4", DateTimeSent = DateTime.Now, Delete = false });
myPrivateMessages.Add(new PrivateMessage { From = "abc4#abc.com", Subject = "Subject 5", Message = "Message 5", DateTimeSent = DateTime.Now, Delete = false });
return myPrivateMessages;
}
}
}
Controller class
namespace Mvc3Application1.Controllers {
public class PrivateMessageController : Controller
{
//
// GET: /PrivateMessage/
// Show all the private messages
public ActionResult ListMessages()
{
return View(new Models.PrivateMessageRepository().GetPrivateMessages());
}
//delete the selected messages and return the collection
[HttpPost]
public ActionResult ListMessages(FormCollection collection)
{
List<Models.PrivateMessage> messages = new Models.PrivateMessageRepository().GetPrivateMessages();//all messages
List<Models.PrivateMessage> cloneMessages = new List<Models.PrivateMessage>();//messages left for deletion
int noOfItems = 0;//no of items deleted
int currentItem = 0;//current item in collection 'messages'
string[] deletedItems = collection[0].Split(',');//return from HTML control collection
for (int i = 0; i < deletedItems.Length; i++)
{
if (bool.Parse(deletedItems[i]) == false)//if checkbox is unchecked
{
cloneMessages.Add(messages[currentItem]);//copy original message in cloneMessages collection
}
else //if checkbox is checked
{
noOfItems++;
i++;
}
currentItem++;
}
ViewBag.Items = noOfItems + " message(s) deleted.";
return View(cloneMessages);
}
} }
View
#model IEnumerable<Mvc3Application1.Models.PrivateMessage>
#{
ViewBag.Title = "Private Messages";
}
<h2>Private Messages</h2>
<div style="color:green;font-weight:bold;">#ViewBag.Items</div>
<br />
#using (Html.BeginForm())
{
<table>
<tr>
<th></th>
<th>
From
</th>
<th>
Subject
</th>
<th>
Message
</th>
<th>
DateTimeSent
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.CheckBoxFor(modelItem => item.Delete)
</td>
<td>
#Html.DisplayTextFor(modelItem => item.From)
</td>
<td>
#Html.DisplayTextFor(modelItem => item.Subject)
</td>
<td>
#Html.DisplayTextFor(modelItem => item.Message)
</td>
<td>
#Html.DisplayTextFor(modelItem => item.DateTimeSent)
</td>
</tr>
}
</table>
<input type="submit" value="Delete"/>
}