Following on from my previous post on using ViewBag and TempData, this post will show you how to use ViewModels so that you can interact with multiple Models in one object and pass its properties to a View.
ViewModels are strongly typed, so they give you the following advantages over ViewBag:
- Compile-time checking (ViewBag is dyanamically typed, so you’ll only see any issues at run time).
- Intellisense (it’s worth using ViewModels for this functionality alone!)
- Your Data Annotations in the ViewModel won’t be removed, like they are with Database Models when you add to/refresh the Entity diagram.
When we create a ViewModel, all we’re really doing is combining two Models from our database, into one ViewModel which will exist as a Class.
Creating a ViewModel
In Visual Studio I tend to keep my ViewModels in a ViewModels folder. But they can also be referenced from an imported DLL if required.
Continuing with the Car theme, here’s the ViewModel that we’d create:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
namespace CarApp.ViewModels { public class TuningCarViewModel { public int ID { get; set; } public string Make { get; set; } public string Model { get; set; } public string Colour { get; set; } public int TuningID { get; set; } public string TurboType { get; set; } public bool SuspensionUpgraded { get; set; } } } |
Getting the data to the View, via the Controller
You create an instance of your ViewModel the same way you would create an instance of any other Model.
1 2 3 4 5 |
public ActionResult Details(int id = 0) { tblCar car = db.tblCars.Find(id); return View(CarToTuningCar(car)); } |
So we find the Car for the ID that’s been supplied. We then pass this car to another method CarToTuningCar which will convert the Car object into a TuningCarViewModel.
If you don’t have many properties to map, you can do it manually as shown below. But this can become time-consuming if you have lots of properties. In this case, you might want to try out AutoMapper.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
private TuningCarViewModel CarToTuningCar(tblCar car) { TuningCarViewModel tcvm = new TuningCarViewModel(); // here we set the properties of the new object (tcvm) // based on the properties of the existing object (car) tcvm.ID = car.ID; tcvm.Make = car.Ward; tcvm.Model = car.Activity; tcvm.Colour = car.Category; tvcm.TuningID = car.NoAttending; tcvm.TurboType = car.ActivityDate; tcvm.SuspensionUpgraded = car.StaffAssignmentNo; tcvm.TuningID = car.TuningID; //I'm assuming you have a foreign key to // link to the Tuning table // now we set the properties that have come from the other Model (Tuning) // we use the TuningID to find the relevant record in the Tuning table tcvm.TurboType = GetTurboType(car.TuningID); tcvm.SuspensionUpgraded = GetSuspensionUpgraded(car.TuningID); return wamh; } |
We use the methods below to get the actual values from the Tuning table:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
private string GetTurboType(int? TuningID) { string turboType; turboType = db.tblTuning.Find(TuningID).TurboType; return turboType; } private bool GetSuspensionUpgraded(int? TuningID) { bool suspensionUpgraded; suspensionUpgraded = db.tblTuning.Find(TuningID).SuspensionUpgraded; return suspensionUpgraded; } |
Rendering in the View
We need to ensure that the View uses our new ViewModel, so update it accordingly:
1 |
@model CarApp.ViewModels.TuningCarViewModel |
You can then access the properties of the ViewModel as usual:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<div class="editor-label"> @Html.LabelFor(model => model.TurboType) </div> <div class="editor-field"> @Html.DisplayFor(model => model.TurboType) </div> <div class="editor-label"> @Html.LabelFor(model => model.SuspensionUpgraded) </div> <div class="editor-field"> @Html.DisplayFor(model => model.SuspensionUpgraded) </div> |
Conclusion
ViewModels in ASP.NET allow us to work with multiple Models and present their data in one View. Once you’ve got past the initial trickyness, you’ll find they over you advantages over using ViewBag and TempData.