MVC ViewModel not posting back - asp.net-mvc

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 ?

Related

How to fetch one row from db in asp mvc

ASP.net mvc in new for me, for some time I used php (no mvc), but now i'm interested, how I can fetch one row from db? without foreach, for example in title...
here is some code:
controller
public ActionResult Index()
{
var pages = (from page in db.Pages where page.PageName == "index" select page).ToList();
return View(pages);
}
view:
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
<% foreach (var item in Model)
{ %>
<%= Html.Encode(item.Text) %>
<% }
%>
</asp:Content>
In your controller, instead of .ToList() you can use the .FirstOrDefault() method, this will return only the first row from the database.
Then in your view you won't need the foreach.
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
<%= Html.Encode(item.Model.Text) %>
</asp:Content>
What you're doing there is creating a List datatype variable and passing it in as the Model to your view. Assuming this is the only piece of data your page needs. Here's what you would do;
public ActionResult Index()
{
string page = db.pages.where(p => p.PageName == "index").FirstOrDefault().PageName;
return View(page);
}
There in your page, Model will now be that single string value and you can do this;
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
<%= Model %>
</asp:Content>
Although it is best practice to create a ViewModel for the page with the just the properties your page will need and pass that in as the Model.
public class MypageViewModel
{
public string PageName { get; set; }
}
Then do this in the controller
public ActionResult Index()
{
MypageViewModel MyModel = new MypageViewModel();
MyModel.PageName = db.pages.where(p => p.PageName == "index").FirstOrDefault().PageName;
return View(MypageViewModel);
}
Hope that helps.
If you are using Entity Framework:
var singleItem = db.pages.Find(id);
This will use the Primary Key of your entity.
If you have a composite primary key consisting of multiple properties, Find will still work (because it can take multiple values):
var singleItem = db.pages.Find(key1, key2);

ASP.net MVC2 Passing data between strongly typed views

I have the following MVC2 view that is strongly typed with a viewmodel, the viewmodel contains a list of values from one db table, I need to display a single value from a second table in the view, this is my view code
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<CustomerDatabase.WebUI.Models.CustomerSitesListViewModel> " %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Customer Sites
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<% foreach (var customerSite in Model.CustomerSites) { %>
<% Html.RenderPartial("CustomerSiteSummary", customerSite); %>
<%} %>
</asp:Content>
This is the viewmodel, notice i am including a Customer member in the viewmodel as i want to display the customer name in addition to the list of customer sites
namespace CustomerDatabase.WebUI.Models
{
public class CustomerSitesListViewModel
{
public IList<CustomerSite> CustomerSites { get; set; }
public PagingInfo PagingInfo { get; set; }
public Customer customer { get; set; }
}
}
This is my controller code for the view
public ViewResult List([DefaultValue(1)] int page)
{
var customerSitesToShow = customerSiteRepository.CustomerSites;
var viewModel = new CustomerSitesListViewModel
{
CustomerSites = customerSitesToShow.Skip((page - 1) * PageSize).Take(PageSize).ToList(),
PagingInfo = new PagingInfo
{
CurrentPage = page,
ItemsPerPage = PageSize,
TotalItems = customerSitesToShow.Count()
}
};
return View(viewModel); //Passed to view as ViewData.Model (or simply model)
}
This is my partial view that renders the list,
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CustomerDatabase.Domain.Entities.CustomerSite>" %>
<div class="item">
<div class="customer-list-item">
<h2><%:Model.customer.CustomerName%></h2>
<%: Model.AddressLine1 %>
<%: Model.AddressLine2%>
Although intellisense lets me access the customer object from the view with
<h2><%:Model.customer.CustomerName%></h2>
An error is thrown when i navigate to the view,
Object reference not set to an instance of an object.
Source Error:
Line 7: <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
Line 8: <% foreach (var customerSite in Model.CustomerSites) { %>
Line 9: <%:Model.customer.CustomerName%>
Line 10: <% Html.RenderPartial("CustomerSiteSummary", customerSite); %>
Line 11: <%}
I think the error is due to the view rendering a list, i tried changing the viewmodel member to
public IList<Customer> {get; set;}
but this doesn't work either.
Can anyone suggest a way i can achieve this or offer any advice on where i am going wrong this is one problem i haven't been able to resolve after hours or researching on the Internet?
It looks like one of the model properties are not initialized. If you add a breakpoint on that line and check the variables I'm pretty sure you'll find 1 that is null.

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.

Pass SelectList "SelectedValue" to Controller Action Method

I have a registration form which displays a users Name (textbox), Email (textbox) and Division (SelectList). The Name and Email are pre-populated (I'm using Windows Authentication, Intranet app), and I want to send the SelectedValue from the DropDown to my controller as an Int32, I don't want to send the entire SelectList back. This list is small now, but will grow to considerable size.
I a class called RegistrationViewModel, it contains public properties for these fields. However, when I use SelectList for the DivisionList, I receive this error: No parameterless constructor defined for this object..
If i change the Type, it works no problem, but Division is null or 0. Is there a way to pass the SelectedValue from a DropDown to a Controller Action method as a Int32?
Edit 1:
I'm not really sure what I'm doing, I've been using MVC for about 48 hours, watched the PDF, TechEd, and TechDays videos.
My apologies, here is my controller code:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Register(RegistrationViewModel rvm)
{
IApplicationContext context = ContextRegistry.GetContext();
IValidationErrors errors = new ValidationErrors();
IValidator validator = (IValidator)context.GetObject("RegistrationValidator");
bool valid = validator.Validate(rvm, errors);
if (valid)
repo.SaveRegistration();
else
ViewData["DivisionList"] = repo.GetDivisions();
return View(rvm);
}
RegistrationViewModel Class
public class RegistrationViewModel
{
public string Name { get; set; }
public string Email { get; set; }
//public SelectList DivisionList { get; private set; }
public int Division { get; set; }
}
Here's the view
<%# Page Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<RegistrationViewModel>" %>
<%# Import Namespace="Project1.Entities"%>
<%# Import Namespace="Project1.Models"%>
<asp:Content ID="registerTitle" ContentPlaceHolderID="TitleContent" runat="server">
Register
</asp:Content>
<asp:Content ID="registerContent" ContentPlaceHolderID="MainContent" runat="server">
...
<% using (Html.BeginForm())
{ %>
<div>
<fieldset>
<legend>Account Information</legend>
<p>
<label for="name">Name:</label>
<%= Html.TextBox("Name", User.Identity.Name.GetDisplayName()) %>
<%= Html.ValidationMessage("username") %>
</p>
<p>
<label for="email">Email:</label>
<%= Html.TextBox("email", User.Identity.Name.GetEmailFromLogin()) %>
<%= Html.ValidationMessage("email") %>
</p>
<p>
<label for="division">Division:</label>
<%= Html.DropDownList("DivisionList", ViewData["DivisionList"] as SelectList)%>
<%= Html.ValidationMessage("confirmPassword") %>
</p>
<p>
<input type="submit" value="Register" />
</p>
</fieldset>
</div>
<% } %>
</asp:Content>
Edit 2:
Eilon: Here is what I changed it too:
Controller:
public ActionResult Register()
{
ViewData["DivisionList"] = repo.GetDivisions();
return View();
}
View:
<%= Html.DropDownList("DivisionValue", ViewData["DivisionList"] as SelectList)%>
I recieve this exception:
There is no ViewData item with the key 'DivisionValue' of type 'IEnumerable'.
When I updated the View to this:
<%= Html.DropDownList("DivisionList", ViewData["DivisionList"] as SelectList)%>
It works just great! It only seems to work if all the "Division" items named identically. If I change the name the View crashes or the ViewModel "Division" property is sent as 0.
Why is that?
The RegistrationViewModel type should contain a simple-typed property such as:
public string DivisionValue { get; set; }
Or change the type to int, DateTime, or whatever the appropriate type is.
In HTML and HTTP the only thing that gets posted back for a drop down list is the name of the field and the selected value.
To get everything to match up you also need to change the view to render a different input name for the drop down list:
<%= Html.DropDownList("DivisionValue", ViewData["DivisionList"] as SelectList)%>
Notice that I'm using "DivisionValue" is the value of the list, and DivisionList as the list of all available items.
I'd just be more explicit with the SelectList type. I'd suggest creating the SelectList in the controller action and forget about casting it in the view. My code works like this (CRUD Edit page):
..in the Action:
ViewData["WorkType.ID"] = new SelectList(this._vacancySvc.GetVacancyWorkTypes(),
"ID", "Name", ViewData["WorkType.ID"] ?? vacancy.WorkType.ID);
..and in the view:
<p><% =Html.Encode("Work Type:") %><br />
<% =Html.DropDownList("Worktype.ID")%><span class="smallgrey">(required)</span><br />
.. you can see that either the initial selection (from DB) is persisted or the ViewData from post backs (like if the form fails validation) thru the use of the [null coalescing operator][1] (??).
Moreover, if i refactored this code, i'd prob like to use a ViewModel object like you are.
The only thing is: (1) you'd never need to reference the ViewModel SelectList property in the view coz MVC auto binds this for us by the Html.DropDownList() overload.. and (2) i'd still need to ref the ViewData in the action anyway to get the selected value from a failed validation post back so what's the point really??

Resources