I am currently stuck at some point of my implementation where I use a ViewModel class to display data, but I need to post values from other object which are equal to given values in the ViewModel. Here are both model classes
ViewModel.cs
public class ViewModel
{
public IList<Answer> Answers { get; set; }
public Question Questions { get; set; }
}
UserScore.cs
public partial class UserScore
{
public int ScoreID { get; set; }
public int U_Id { get; set; }
public int A_Id { get; set; }
public bool CorrectAnswer { get; set; }
public int Q_Id { get; set; }
public virtual Answer Answer { get; set; }
public virtual Member Member { get; set; }
public virtual Question Question { get; set; }
}
So far so good. I am using an object of Question and List of Answers to display the data I need in my Controller
Controller.cs
public ActionResult TakeTest(int id=0)
{
ViewModel vm = new ViewModel();
Test t = db.Tests.Find(id);
if (t == null)
{
return HttpNotFound();
}
vm.Questions = (from q in db.Questions
join tt in db.Tests on q.BelongToTest equals tt.TestId
where q.BelongToTest == id
select q).FirstOrDefault();
vm.Answers = new List<Answer>(from a in db.Answers
join q in db.Questions on a.BelongToQuestion equals q.QuestionId
join tt in db.Tests on q.BelongToTest equals tt.TestId
where q.BelongToTest == id &&
a.BelongToQuestion == vm.Questions.QuestionId
select a).ToList();
foreach (var i in vm.Answers)
{
i.CorrectOrNot = false;
}
return View(vm);
}
View.cshtml
#model MvcTestApplication.Models.ViewModel
#using MvcTestApplication.Models
#{
ViewBag.Title = "TakeTest";
}
<h2>TakeTest</h2>
#using (Html.BeginForm()) {
<table>
<tr>
<th>Question Name</th>
</tr>
<tr>
<td>#Html.DisplayFor(model => model.Questions.Question_Text)</td>
</tr>
</table>
<table id="dataTable">
<tr>
<th>Correct?</th>
<th>Answer text</th>
<th>Open Answer</th>
</tr>
#for(int i = 0; i < Model.Answers.Count; i++)
{
<tr>
<td>#Html.CheckBoxFor(m => m.Answers[i].CorrectOrNot)</td>
<td>#Html.DisplayFor(m => m.Answers[i].AnswerText)</td>
<td>#Html.EditorFor(m => m.Answers[i].OpenAnswerText)</td>
</tr>
}
</table>
if(ViewBag.Message != null)
{
<script>
$(document).ready(function(){
alert('#ViewBag.Message');
});
</script>
}
<input type="submit" value="Next Question" />
}
Now in my post method I need to get the value of vm.Question.QuestionId and AnswerId of the Answer list, set them to be equal to UserScore.Q_Id and UserScore.A_Id. How can I do that ? I tried many ways but with no success.
Controller.cs
[HttpPost]
[Authorize]
public ActionResult TakeTest(ViewModel vm)
{
if (ModelState.IsValid)
{
UserScore us = new UserScore();
us.U_Id = (from m in db.Members
where m.UserID == WebSecurity.CurrentUserId
select m.MemberId).FirstOrDefault();
us.A_Id = 49;
//us.A_Id = vm.Questions.QuestionID returns NULL
us.Q_Id = 150;
db.UserScores.Add(us);
db.SaveChanges();
}
return View(vm);
}
In general I need to know how to bind this vm.something to us.something because Question appears to be null all the time.
These values are null, because they are not present in your view. You will need to keep them in your View in the form of a hidden control. The ViewModel that you receive in the post can only construct the ViewModel using values present in the View. Since there is no ID maintained in the View, the constructed ViewModel has a null ID.
You can use
#Html.HiddenFor(model => model.Questions.ID)
and for your answer ID
#Html.HiddenFor(m => m.Answers[i].ID)
vm.Questions.QuestionID returns NULL because u haven't used that on the view anywhere. A easy hack would be to use a hidden field to capture the value or you should be initializing your viewmodel again and follow the logic in the post method.
You should use an hiddenfor helpers in your view and try something like that.
#Html.hiddenfor(m=>vm.Questions.QuestionId)
Give it a try : Html.HiddenFor value property not getting set
Related
public class StudentViewModel
{
public Student studentVm { get; set; }
public StudentAdditionalInfo studentAdditionalInfoVm { get; set; }
public int rcImgToProcess { get; set; }
}
studentVm and studentAdditionalInfoVm stores the data of my 2 Tables Student and StudentAdditionalInfo, these contains multiple records
rcImgToProcess store the data of the record count that I passed from my controller, so it is only a single data (I can use ViewBag but for some reason I prefer passing it to Model)
<div>
I want the value of [rcImgToProcess] here
</div>
#foreach (var item in Model)
{
<tr>
<td>#item.studentVm.Id </td>
<td>#item.studentVm.StudentCourse</td>
<td>#item.studentAdditionalInfoVm.MotherName</td>
<td>#item.studentAdditionalInfoVm.FatherName</td>
</tr>
}
Controller
int rcImgToProcess = "0";
rcImgToProcess= 1001;
var studentList = from s in student
join st in studentAdditionalInfo on s.Id equals st.Id into st2
from st in st2.DefaultIfEmpty()
select new StudentViewModel {
studentVm = s,
studentAdditionalInfoVm = st,
rcImgToProcess = rcImgToProcess
};
return View(studentList);
How can I call rcImgToProcess to display on the header part of the page
are you referencing the StudentViewModel in the view correctly?
you should have #model <namespaceForStudentViewModel>.StudentViewModel at the top of the file.
eg #model SampleApplication.ViewModels.StudentViewModel
then you can use <div>#Model.rcImgToProcess</div> anywhere in the view
I have a number of awards in my view and within each award there is a corresponding list of qualifications. I have created a ViewModel to display each award and with a click of a button a modal should appear with its relevant qualifications which can be marked as completed/updated by the user. However on the Post of the data it is not binding to my ViewModel in my controller method. The data is appearing in my view as expected with each Award only showing its relevant qualifications. I have used FormCollection to access some of the fields for testing purposes and the data is being posted back. Any help would be great!
ViewModel
public class CandidateExtended
{
public CandidateExtended()
{
this.Qualifications = new List<Qualification_Extended>();
}
public int AwardID { get; set; }
public int FrameworkID { get; set; }
public string ULN { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
public string TitleShort { get; set; }
public string TitleFull { get; set; }
public DateTime DOB { get; set; }
public string Award { get; set; }
public int AwardLevel { get; set; }
public string Status { get; set; }
public string Completion { get; set; }
public string SelectedRoute { get; set; }
public List<Qualification_Extended> Qualifications { get; set; }
public void addQualification(Qualification_Extended qualification)
{
Qualifications.Add(qualification);
}
}
Controller
[HttpGet]
public ActionResult Index()
{
var awardDetails = (from award in db.award
join candidate in db.candidate
on award.ULN equals candidate.ULN
join framework in db.framework
on award.QAN equals framework.QAN
where award.OrganisationIdentityID == organisationID
select new AwardDetails_Extended
{
AwardID = award.AwardID,
ULN = award.ULN,
AwardStatus = award.AwardStatus,
Forename = candidate.Forename,
Surname = candidate.Surname,
DOB = candidate.DOB,
FrameworkID = framework.FrameworkID,
TitleFull = framework.TitleFull,
TitleShort = framework.TitleShort,
AwardLevel = framework.AwardLevel,
Award = framework.Award,
Completion = framework.Completion
}).ToList();
var qualificationDetails = (from candidateQualification in db.candidateQualification
join qualification in db.qualification
on candidateQualification.QualificationID equals qualification.QualificationID
select new Qualification_Extended
{
ID = candidateQualification.ID,
QualificationID = candidateQualification.QualificationID,
ULN = candidateQualification.ULN,
FrameworkID = candidateQualification.FrameworkID,
Achieved = candidateQualification.Achieved,
DateAchieved = candidateQualification.DateAchieved
}).ToList();
List<CandidateExtended> candidateVM = new List<CandidateExtended>();
foreach (var item in awardDetails)
{
CandidateExtended vm = new CandidateExtended();
vm.AwardID = item.AwardID;
vm.FrameworkID = item.FrameworkID;
vm.ULN = item.ULN;
vm.Forename = item.Forename;
vm.Surname = item.Surname;
vm.DOB = item.DOB;
vm.TitleShort = item.TitleShort;
vm.TitleFull = item.TitleFull;
vm.Award = item.Award;
vm.AwardLevel = item.AwardLevel;
vm.Status = item.AwardStatus;
vm.Completion = item.Completion;
vm.SelectedRoute = item.SelectedRoute;
foreach (var qualification in qualificationDetails)
{
if (qualification.ULN == item.ULN && qualification.FrameworkID == item.FrameworkID)
{
vm.addQualification(qualification);
}
}
candidateVM.Add(vm);
}
return View(candidateVM);
}
View
#using (Html.BeginForm("UpdateAward", "Organisation", FormMethod.Post))
{
#Html.HiddenFor(a => award.AwardID)
<div class="row">
<div class="col-md-12">
<div class="row org-row-main">
<div class="col-md-7"><h4 class="org-type">Qualification</h4></div>
<div class="col-md-2"><h5 class="org-completed">Completed</h5></div>
<div class="col-md-3"><h5 class="org-date">Date</h5></div>
</div>
<hr class="org-hr"/>
#for (int i = 0; i < award.Qualifications.Count(); i++)
{
var qualification = award.Qualifications[i];
<div class="row org-row">
<div class="col-md-7">
#Html.HiddenFor(a => award.Qualifications[i].ID)
</div>
<div class="col-md-2">
#Html.CheckBoxFor(a => award.Qualifications[i].Achieved)
</div>
<div class="col-md-3">#Html.TextBoxFor(a => award.Qualifications[i].DateAchieved, "{0:dd/MM/yyyy}")
</div>
</div>
}
</div>
</div>
<button type="submit" class="btn admin-button" style="margin-top: 0;">Save</button>
}
UpdateAward
[HttpPost]
public ActionResult UpdateAward(CandidateExtended model, FormCollection collection)
{
return RedirectToAction("Index", "Login");
}
First (and you may already have this, but we can't see it): your View should start with a line containing #model List<CandidateExtended> (prefix the inner Type with the proper namespace).
Then in the View you should use Model, which is by definition of the exact type specified after the #model keyword.
We see that you are using award, we can't see where it comes from, presumably it is set using something like var award = Model[j] or foreach (var award in Model).
Never use such temporary or helper variables (for efficiency) in a View to render a Form; the View needs the fully qualified name of all objects, e.g. Model.Item[x].SubItem[y] in order to generate Form field names that can be used for Model Binding.
E.g. this : #Html.HiddenFor(a => award.Qualifications[i].ID)
should be: #Html.HiddenFor(a => Model[j].Qualifications[i].ID)
And make the same change in all other places.
Then do as was already suggested, use the List<...> in your Controller Post method.
Finally also please remove the FormCollection, it is not needed if you have everything set up as described here. Decent MVC code never uses FormCollection, ever.
Try calling the posted method on a separate button instead of BeginForm and it should work.
In my Products PartiallView table
#model IEnumerable<Products.Models.ProductModelView>
I'am trying (hide) not showing some buttons if user departmentId is not the same as product departmentId
<table class="table table-responsive table-hover table-striped">
<tr>
<th>Product type</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.ProductName)
</td>
// I want to hide if current inlogged userDepartmentId is not the same as product departmentId
// Like #if(#item.ProductDeptId == userDepartmentId) {
<td>
<Button class="btn btn-success glyphicon btn-xs glyphicon-plus" onclick="return EditDelete(#(item.ProductId) )">Edit/Delete</Button>
</td>
}
</tr>
}
Here is my Class, ViewModel and Action that I'am trying to create but don't know how to pass to my PartielView
public class Product
{
public int ProductId { get; set; }
public string productName { get; set; }
public int DepartmentId { get; set; }
}
public class ProductModelView
{
public int ProductId { get; set; }
public string productName { get; set; }
public int DepartmentId { get; set; }
public int UserDepartmentId { get; set; }
}
[HttpGet]
public ActionResult Lager()
{
using (context)
{
string user = User.Identity.Name;
int deptId = context.Users.Where(u => u.UserName == user).Select(d => d.DepartmentId).SingleOrDefault();
// Here I don't know how to continue ... I try like this
Product pr = new Product();
ProductModelView prModel = new ProductModelView();
prModel.ProductId = pr.ProductId;
prModel.productName = pr.productName ;
prModel.DepartmentId= pr.DepartmentId;
prModel.UserDepartmentId = DeptId;
// And then, how to return and what to return?
return PartialView("_ProductList", prModel); // Is this right? Returning prModel?
}
Can anyone please help me to formulate my Class, ViewModel and my Action?
Create a "composite" object and pass it instead (as per #Uwe):
public class ProductListViewModel
{
public IEnumerable<ProductModelView> Products { get; set; }
}
and change #model accordingly:
#model ProductListViewModel
Or construct and pass IEnumerable<ProductModelView> products to return PertialView():
// IQueryable<Product>
var products = from p in context.Products
where p.DepartmentId == depId // aware! would cause 2 queries to db, shall be rewritten
select p;
var prModels = from p in products.AsEnumerable() // 'memorize' db query into in-memory objects
select new ProductViewModel
{
ProductId = p.ProductId,
ProductName = p.productName,
DepartmentId = p.DepartmentId;
UserDepartmentId = deptId;
};
return return PartialView("_ProductList", prModels);
How to rewrite:
Either configure a navigation property (recommended):
public class Product
{
public User { get; set; }
}
Or perform a direct join:
var products = from p in context.Products
join u in context.User on p.UserDepartmentId = u.UserDepartmentId // or whatever it is
where u.UserName == userName // it's better to use userId which is likely the primary key
select p;
I am working on an online library using ASP.NET MVC.
This is my view model for the library management page:
public class ManageViewModel
{
public IPagedList<ManageBookViewModel> WholeInventory;
public IPagedList<ManageBookViewModel> CurrentInventory;
public bool OldInventoryIsShown { get; set; } = false;
}
In the corresponding view I have a checkbox for whether or not to show the old inventory and a local variable modelList, which I would like to set to Model.WholeInventory if the checkbox is checked and to Model.CurrentInventory otherwise. I use modelList to display a table with all the books and I would need its value to be reset every time I (un)check the checkbox in order for the list to be properly displayed.
Is this possible? How would I go about doing this?
In my view I currently have:
<label class="switch">
<input id="OldInventoryIsShown" name="OldInventoryIsShown" type="checkbox" />
<span class="slider round"></span>
</label>
#{
var modelList = Model.OldInventoryIsShown ? Model.WholeInventory : Model.CurrentInventory;
}
#using (Html.BeginForm())
{
<table id="bookInventory" class="table table-hover">
<thead>
<tr>
<th>Author</th>
<th>Title</th>
....
</tr>
</thead>
#foreach (var entry in modelList)
{
<tr>
<td>#Html.DisplayFor(modelItem => entry.Author)</td>
<td>#Html.DisplayFor(modelItem => entry.Title)</td>
....
</tr>
}
</table>
<p>Page #(modelList.PageCount < modelList.PageNumber ? 0 : modelList.PageNumber) of #modelList.PageCount</p>
#Html.PagedListPager(modelList, page => Url.Action("Manage", page }))
}
The controller action:
public ActionResult Manage(int? page)
{
var wholeInventory = _bookService.GetBooksIncludingDisabled().Select(b => Mapper.Map<Book, ManageBookViewModel>(b));
var currentInventory = _bookService.GetBooks().Select(b => Mapper.Map<Book, ManageBookViewModel>(b));
int pageSize = 3;
int pageNumber = page ?? 1;
var model = new ManageViewModel
{
WholeInventory = wholeInventory.ToPagedList(pageNumber, pageSize),
CurrentInventory = currentInventory.ToPagedList(pageNumber, pageSize)
};
return View(model);
}
Models:
Book.cs
public class Book
{
public int BookId { get; set; }
[Required]
[MinLength(1)]
public string Title { get; set; }
[Required]
[MinLength(1)]
public string Author { get; set; }
....
public bool IsDisabled { get; set; } = false;
public virtual ICollection<UserBook> UserBooks { get; set; }
}
ManageBookViewModel.cs
public class ManageBookViewModel
{
public int BookId { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "Enter the book title")]
public string Title { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "Enter the book author.")]
public string Author { get; set; }
....
public bool IsDisabled { get; set; }
}
Your ManageViewModel needs to include only one property for the paged list and it should be IPagedList<Book> (see explanation below)
public class ManageViewModel
{
public IPagedList<Book> Inventory;
[Display(Name = "Include old inventory")]
public bool OldInventoryIsShown { get; set; }
... // any other search/filter properties
}
and your view needs to include the checkbox inside the <form> element, and the form should be making a GET to your controller method. Then you also need to include the current value of OldInventoryIsShown as a route value in the #Html.PagedListPager() method so that the current filter is retained when paging.
#model ManageViewModel
...
#using (Html.BeginForm("Manage", "ControllerName", FormMethod.Get))
{
#Html.CheckBoxFor(m => m.OldInventoryIsShown)
#Html.LabelFor(m => m.OldInventoryIsShown)
... // any other search/filter properties
<input type="submit" value="search" />
}
<table id="bookInventory" class="table table-hover">
....
</table>
<p>Page #(modelList.PageCount < modelList.PageNumber ? 0 : modelList.PageNumber) of #modelList.PageCount</p>
#Html.PagedListPager(modelList, page =>
Url.Action("Manage", new { page = page, oldInventoryIsShown = Model.OldInventoryIsShown })) // plus any other search/filter properties
Finally in the controller method you need a parameter for the value of the bool property an modify your query based on that value.
public ActionResult Manage(int? page, bool oldInventoryIsShown)
{
int pageSize = 3;
int pageNumber = page ?? 1;
IQueryable<Book> inventory = db.Books;
if (!oldInventoryIsShown)
{
inventory = inventory.Where(x => !x.IsDisabled);
}
ManageViewModel model = new ManageViewModel
{
Inventory = inventory.ToPagedList(pageNumber, pageSize),
OldInventoryIsShown = oldInventoryIsShown
};
return View(model);
}
You current controller code is terribly inefficient. Lets assume your table has 10,000 Book records, and 5,000 of those are 'disabled' (archived). You current code first gets all 10,0000 records and adds them to memory. Then you map all then to a view model. Then you call another query to get another 5,0000 records (which are just duplicates of what you already have), which you add to memory and map to a view model. But all you want in the view is 3 records (the value of pageSize) so you have done thousands of times of extra unnecessary processing.
In your case, there is no need for a view model (although if you did need one, you would use the StaticPagedList methods - refer this answer for an example). Your query should be using your db context to generate an IQueryable<Book> so that only the results you need are returned from the database (internally the ToPagedList() method uses .Skip() and .Take() on IQueryable<T>)
I've inherited my first MVC project and it involves using MVC3 on top of Linq to SQL. I've been trying to find a way to generate a check box list based on a many to many relationship involving a cross table.
I have a systemFailureType table that maps to a SystemFailureProblem table via a cross table.
Here is my designer layout for the tables:
And here are my models:
[MetadataType(typeof(SystemFailureProblemMetadata))]
public partial class SystemFailureProblem
{
private class SystemFailureProblemMetadata
{
public int ID { get; set; }
[Required]
[StringLength(200)]
[DisplayName("Problem Description")]
public String Description { get; set; }
public IList<xSystemFailureProblemToType> FailureTypeCategories { get; set; }
}
}
[MetadataType(typeof(SystemFailureTypeMetaData))]
public partial class SystemFailureType
{
private class SystemFailureTypeMetaData
{
public int ID { get; set; }
[Required]
[StringLength(200)]
public String Description { get; set; }
}
}
My current view code uses a view model that contains a problem object. So the current code I have for generating the checkbox list looks like this:
#for(int i=0;i < Model.problem.FailureTypeCategories.Count(); i++)
{
#Html.CheckBox("FailureTypeCategories["+i+"].ID", false)
}
My main issue is that I'm getting some errors when I try to generate the checkbox list saying that the FailureTypeCategories collection doesn't exist. I suspect it may be related to how I have the models set up currently. My initial thoughts are leaning towards implementing a model for the cross table, though I'm not quite sure how I would integrate that. Is there an different way I should be going about this, or am I on the right track and just missing something?
Edit:
Here is the ViewModel
public SystemFailureProblem problem { get; set; }
public SystemFailureProblemViewModel() { }
public SystemFailureProblemViewModel(SystemFailureProblem problem)
{
this.problem = problem;
}
The controller method is very simple. It just returns a partial view of the form.
public ActionResult Edit(int id)
{
try
{
return PartialView("Form", context.SystemFailureProblems.Single(p => p.ID == id));
}
catch (Exception ex)
{
ModelState.AddModelError("", ex.Message);
return PartialView("Form", null);
}
}
I came up with an idea based on this article which utilizes Entity Framework, but it wasn't too difficult to translate into LinqToSql classes.
First, I tweaked the ViewModel class. You'll need to store more information in there other than the SystemFailureProblem object, such as information pertinent to the collection of SystemFailureType assigned to that problem.
public class SystemFailureProblemTypeViewModel
{
public int TypeID { get; set; }
public string TypeDescription { get; set; }
public bool Assigned { get; set; }
}
Next, I created the logic for the Edit actions (GET and POST). In the GET method, you find out which types are currently selected for the problem (from xSystemFailureProblemToType table) and construct a ViewModel using that data. This ViewModel gets passed to the View along with the SystemFailureProblem object.
public ActionResult Edit(int id)
{
SystemFailureProblem problem = (from p in context.SystemFailureProblems
where p.ID == id
select p).Single();
PopulateSystemFailureProblemData(problem);
return View(problem);
}
public void PopulateSystemFailureProblemData(SystemFailureProblem problem)
{
// get all failure types
var allTypes = from t in context.SystemFailureTypes select t;
// get al types joined with this problem using cross table
var problemTypes = from x in context.xSystemFailureProblemToTypes
join t in context.SystemFailureTypes on x.SystemFailureTypeID equals t.ID
where x.SystemFailureProblemID == problem.ID
select t;
// construct view model collection
List<SystemFailureProblemTypeViewModel> viewModel = new List<SystemFailureProblemTypeViewModel>();
foreach (var type in allTypes)
{
viewModel.Add(new SystemFailureProblemTypeViewModel
{
TypeID = type.ID,
TypeDescription = type.Description,
Assigned = problemTypes.Contains(type)
});
}
ViewBag.Types = viewModel;
}
In the POST method, we get a string[] parameter that tells us which checkboxes were checked. It is a list of SystemFailureType IDs. Loop through each SystemFailureType in the database, determine which ones are selected/unselected, and update xSystemFailureProblemToType table accordingly.
[HttpPost]
public ActionResult Edit(int id, FormCollection collection, string[] selectedTypes)
{
SystemFailureProblem problem = (from p in context.SystemFailureProblems
where p.ID == id
select p).Single();
// get all types joined with this problem using cross table
var problemTypes = from x in context.xSystemFailureProblemToTypes
join t in context.SystemFailureTypes on x.SystemFailureTypeID equals t.ID
where x.SystemFailureProblemID == problem.ID
select t;
problem.FailureTypes = problemTypes.ToList<SystemFailureType>();
if (TryUpdateModel(problem, "", null, new string[] { "Types" }))
{
try
{
// loop through all types in the system
foreach (var failureType in context.SystemFailureTypes)
{
// determine if checkbox for current type was checked
if (selectedTypes.Contains(failureType.ID.ToString()))
{
// if no joining record exists (type not previously selected), create a joining record
if (!problemTypes.Contains(failureType))
{
context.xSystemFailureProblemToTypes.InsertOnSubmit(
new xSystemFailureProblemToType
{
SystemFailureProblemID = problem.ID,
SystemFailureTypeID = failureType.ID
});
}
}
else
{
// if type was unchecked but joining record exists, delete it
if (problemTypes.Contains(failureType))
{
xSystemFailureProblemToType toDelete = (from x in context.xSystemFailureProblemToTypes
where x.SystemFailureProblemID == problem.ID &&
x.SystemFailureTypeID == failureType.ID
select x).SingleOrDefault();
context.xSystemFailureProblemToTypes.DeleteOnSubmit(toDelete);
}
}
}
context.SubmitChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
PopulateSystemFailureProblemData(problem);
return View(problem);
}
Lastly, I tweaked the View. This code will create 3 columns of checkboxes, the value attribute of each being the SystemFailureType ID it represents.
<div class="editor-field">
<table>
<tr>
#{
int cnt = 0;
List<SystemFailures.Data.SystemFailureProblemTypeViewModel> types = ViewBag.Types;
foreach (var type in types) {
if (cnt++ % 3 == 0) {
#: </tr> <tr>
}
#: <td>
<input type="checkbox"
name="selectedTypes"
value="#type.TypeID"
#(Html.Raw(type.Assigned ? "checked=\"checked\"" : "")) />
#type.TypeDescription
#:</td>
}
#: </tr>
}
</table>
</div>
It may not be the most efficient, but I think it effectively solves the most complicated pieces of your problem. Let me know if I missed anything!