Reputation: 237
I have created a View Model called CompetitionRoundModel
which is partially produced below:
public class CompetitionRoundModel
{
public IEnumerable<SelectListItem> CategoryValues
{
get
{
return Enumerable
.Range(0, Categories.Count())
.Select(x => new SelectListItem
{
Value = Categories.ElementAt(x).Id.ToString(),
Text = Categories.ElementAt(x).Name
});
}
}
[Display(Name = "Category")]
public int CategoryId { get; set; }
public IEnumerable<Category> Categories { get; set; }
// Other parameters
}
I have structured the model this way because I need to populate a dropdown based on the value stored in CategoryValues. So for my view I have:
@using (Html.BeginForm())
{
<div class="form-group">
@Html.LabelFor(model => model.CategoryId, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(model => model.CategoryId, Model.CategoryValues, new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.CategoryId, "", new { @class = "text-danger" })
</div>
</div>
// Other code goes here
}
I have selected model.CategoryId
in the DropDownListFor()
method since I want to bind the selected value to CategoryId
. I really don't care for CategoryValues
, I just need it to populate the DropDown.
My problem now is that when my Controller receives the values for my Model in the action method, CategoryValues
is null which causes the system to throw a ArgumentNullException
(the line that is highlighted is the return Enumerable
line.
I have even tried [Bind(Exclude="CategoryValues")]
but no change at all. Any help would be much appreciated.
Upvotes: 2
Views: 78
Reputation:
Your not (and should not be) creating form controls for each property of each Category
in your IEnumerable<Category>
collection so in your POST method, the value of Categories
is null
(it never gets initialized). As soon as you attempt CategoryValues
and exception is thrown by your .Range(0, Categories.Count())
line of code in the getter.
Change you view model to give CategoryValues
a simple geter/setter, and delete the Categories
property
public class CompetitionRoundModel
{
public IEnumerable<SelectListItem> CategoryValues { get; set; }
[Display(Name = "Category")]
public int CategoryId { get; set; }
.... // Other properties
}
and populate the SelectList
in the controller methods, for example
var categories db.Categories; // your database call
CompetitionRoundModel model = new CompetitionRoundModel()
{
CategoryValues = categories.Select(x => new SelectListItem()
{
Value = x.Id.ToString(),
Text = x.Name
},
....
};
return View(model);
or alternatively
CompetitionRoundModel model = new CompetitionRoundModel()
{
CategoryValues = new SelectList(categories, "Id", "Name" ),
Note also that if you return the view (because ModelState
is invalid, the you need to repopulate the value of CategoryValues
(refer The ViewData item that has the key 'XXX' is of type 'System.Int32' but must be of type 'IEnumerable' for more detail)
Upvotes: 1
Reputation: 50728
Since CategoryValues
just populates the drop down, it will never post back to the server and you'll need to rebuild the list from the database before using it in the GET or POST operation. The CategoryId
property is the value that will be posted back to the server from the DropDownList.
Upvotes: 0