I am building a form for data entry, however one of the drop down lists the user has to fill in is a drop down list that is populated from enums which have been changed to a user friendly format. The drop down list has a default option of 'please select...'. However, no matter what the user selected, when the submit button is clicked and the entry is saved in the database, the saved entry is always the first enum i.e. the value at the top of the list and I can't figure out why.
Here is the model:
public enum Medium
{
[Description("Teleconference & Report")]
Teleconference_Report,
[Description("Email & Telephone")]
Email_Telephone
}
[Required]
[Display(Name = "Medium")]
public Medium Medium { get; set; }
Here is the field in the form:
<div class="form-group">
@Html.LabelFor(model => model.Medium, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-5">
@Html.DropDownList("MediumID", null, "Please select...", htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.Medium, "", new { @class = "text-danger" })
</div>
</div>
The "MediumID" DropDownList is populated using a viewbag which is set to whatever the following returns:
// Puts all of the mediums of communication into a user friendly dropdownlist.
public List<SelectListItem> GetMediumList()
{
List<SelectListItem> mediumList = new List<SelectListItem>();
foreach (Medium state in EnumToList<Medium>())
{
mediumList.Add(new SelectListItem
{
Text = GetEnumDescription(state),
Value = state.ToString(),
});
}
return mediumList;
}
Below shows the form section for another enum called 'Frequency', but these are not changed to user friendly strings, so uses the original EnumDropDownListFor helper.
<div class="form-group">
@Html.LabelFor(model => model.Frequency, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-5">
@Html.EnumDropDownListFor(model => model.Frequency, "Please select...", htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.Frequency, "", new { @class = "text-danger" })
</div>
</div>
Below here, shows the two methods which turn the enums into user friendly strings:
// Returns a 'user friendly', readable version of the enum.
public static string GetEnumDescription(Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes != null && attributes.Length > 0)
return attributes[0].Description;
else
return value.ToString();
}
// Puts all of the same enums into a list.
public static IEnumerable<T> EnumToList<T>()
{
Type enumType = typeof(T);
// Can't use generic type constraints on value types,
// so have to do check like this.
if (enumType.BaseType != typeof(Enum))
throw new ArgumentException("T must be of type System.Enum");
Array enumValArray = Enum.GetValues(enumType);
List<T> enumValList = new List<T>(enumValArray.Length);
foreach (int val in enumValArray)
{
enumValList.Add((T)Enum.Parse(enumType, val.ToString()));
}
return enumValList;
}
Finally, here is the method signature where things get binded/bound:
public ActionResult Create([Bind(Include = "Point,ApplicationID,MediumID,Frequency,StartDate,EndDate")] TouchPoint touchPoint)
Any help is greatly appreciated.
Assuming that you populate ViewBag.MediumList
with GetEnumDescription
method, you need to bind Medium property instead of MediumID and use ViewBag.MediumList as data source for the dropdown:
<div class="form-group">
@Html.LabelFor(model => model.Medium, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-5">
@Html.DropDownListFor(model => model.Medium, (List<SelectListItem>)ViewBag.MediumList, "Please select...", htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.Medium, "", new { @class = "text-danger" })
</div>
Conteoller:
public ActionResult Create([Bind(Include = "Point,ApplicationID,Medium,Frequency,StartDate,EndDate")] TouchPoint touchPoint)
if you still need a MediumId
property - I think you can make it a calculate property:
public int MediumId{
get{
return (int)this.Medium;
}
}
However, no matter what the user selected, when the submit button is clicked and the entry is saved in the database, the saved entry is always the first enum i.e. the value at the top of the list and I can't figure out why
The reason for this is that enum is basically an int and it's default value is 0. When you define your enum in this way:
public enum Medium
{
[Description("Teleconference & Report")]
Teleconference_Report,
[Description("Email & Telephone")]
Email_Telephone
}
Teleconference_Report
value is 0 and Email_Telephone
value is 1 which makes Teleconference_Report
default value for this enum. And since your Medium
property wasn't bound correctly it was always set to default Teleconference_Report
value.