I have the following enum:
public enum EventType : int
{
[Display(Description = "Downtime")]
Downtime = 0,
[Display(Description = "Speed")]
Speed = 1,
[Display(Description = "Quality")]
Quality = 2
}
I am creating a dropdown list for it using:
#Html.EnumDropDownListFor(m => m.Type, "Event Type", new { #class = "form-control" })
The options I get in the dropdown are:
Event Type
Downtime
Speed
Quality
Why on earth is Event Type an option? And what possible value could it represent??
The [Display] attributes are my feeble attempt at fixing this...
Any ideas?
At first you need to create a HTML Helper extension like:
public static class HtmlHelperExtensions
{
private static string GetDisplayName(this Enum enumeration)
{
var enumType = enumeration.GetType();
var enumName = Enum.GetName(enumType, enumeration);
var member = enumType.GetMember(enumName)[0];
var attributes = member.GetCustomAttributes(typeof(DisplayAttribute), false);
var attribute = (DisplayAttribute)attributes[0];
var displayName = attribute.Name;
if (attribute.ResourceType != null)
{
displayName = attribute.GetName();
}
return displayName;
}
public static MvcHtmlString EnumDropDownFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, Func<TEnum, bool> predicate=null, string optionLabel=null, object htmlAttributes=null) where TEnum : struct, IConvertible
{
var enumList = predicate == null ? Enum.GetValues(typeof(TEnum))
.Cast<TEnum>()
: Enum.GetValues(typeof(TEnum))
.Cast<TEnum>()
.Where(e => predicate(e));
var selectList = enumList
.Select(e => new SelectListItem
{
Value = Convert.ToUInt64(e).ToString(),
Text = ((Enum)(object)e).GetDisplayName(),
}).ToList();
if (!string.IsNullOrEmpty(optionLabel))
{
selectList.Insert(0, new SelectListItem
{
Text = optionLabel
});
}
return htmlAttributes==null
? htmlHelper.DropDownListFor(expression, selectList)
: htmlHelper.DropDownListFor(expression, selectList, htmlAttributes);
}
}
Then if your Enum like bellow
public enum EventType
{
[Display(Description = "Downtime")]
Downtime = 0,
[Display(Description = "Speed")]
Speed = 1,
[Display(Description = "Quality")]
Quality = 2
[Display(Description = "Test")]
Test = 3
}
and you are don't want to load Test then use:
#Html.EnumDropDownFor(model => model.Type, types => types != EventType.Test, "Event Type", new {#class = "form-control"})
Or if you need to load all then:
#Html.EnumDropDownFor(model => model.Type, optionLabel:"Event Type", htmlAttributes:new {#class = "form-control"})
Related
I need to display check box list with more than one options. User must select minimum one check box, user can select more than one check boxes.
I want to store values of all check boxes (selected) in one field as a string(Data base) with coma separated. This is not mandatory, mandatory is need to store multiple values of each selected check box. Alternate solutions are welcome.
Model
public class Member
{
public string Member_VehicalType { get; set; }
public IList<SelectListItem> Member_VehicalType_List { get; set; }
Controller
[HttpGet]
public ActionResult Create()
{
Member objMemberModel = new Member();
List<SelectListItem> vehical_Types = new List<SelectListItem>();
vehical_Types.Add(new SelectListItem { Text = "Two Wheeler", Value = "1" });
vehical_Types.Add(new SelectListItem { Text = "Four Wheeler", Value = "2" });
objMemberModel.Member_VehicalType_List = vehical_Types;
return View(objMemberModel);
How do I create view with #Html.CheckBoxFor( or #Html.CheckBox(
I recently had to deal with SelectListItem as a checkbox-list. I came up with the following HtmlExtensions, which might be helpful. These extensions provide the same functionality as the #Html.DropDownListFor(model => ...);
Usage: #Html.CheckBoxListFor(model => model.ModelMemberToPutValueIn, Model.Member_VehicalType_List)
public static class HtmlExtensions
{
public static MvcHtmlString CheckBoxListFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, IEnumerable<SelectListItem> items, object htmlAttributes = null)
{
var listName = ExpressionHelper.GetExpressionText(expression);
var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
items = GetCheckboxListWithDefaultValues(metaData.Model, items);
return htmlHelper.CheckBoxList(listName, items, htmlAttributes);
}
public static MvcHtmlString CheckBoxList(this HtmlHelper htmlHelper, string listName, IEnumerable<SelectListItem> items, object htmlAttributes = null)
{
if (items == null) return null;
var container = new TagBuilder("div");
container.AddCssClass("checkbox-list");
container.MergeAttribute("id", HtmlHelper.GenerateIdFromName(listName));
foreach (var item in items)
{
var id = HtmlHelper.GenerateIdFromName(String.Join(".", listName, item.Text));
var div = new TagBuilder("div");
div.AddCssClass("checkbox");
var cb = new TagBuilder("input");
cb.MergeAttribute("type", "checkbox");
cb.MergeAttribute("id", id);
cb.MergeAttribute("name", listName);
cb.MergeAttribute("value", item.Value ?? item.Text);
if (item.Selected) cb.MergeAttribute("checked", "checked");
var label = new TagBuilder("label");
label.MergeAttribute("for", id);
label.MergeAttributes(new RouteValueDictionary(htmlAttributes), true);
label.InnerHtml = item.Text;
div.InnerHtml = cb.ToString(TagRenderMode.SelfClosing) + label;
container.InnerHtml += div;
}
return new MvcHtmlString(container.ToString());
}
private static IEnumerable<SelectListItem> GetCheckboxListWithDefaultValues(object defaultValues, IEnumerable<SelectListItem> selectList)
{
var defaultValuesList = defaultValues as IEnumerable;
if (defaultValuesList == null) return selectList;
var values = from object value in defaultValuesList select Convert.ToString(value, CultureInfo.CurrentCulture);
var selectedValues = new HashSet<string>(values, StringComparer.OrdinalIgnoreCase);
var newSelectList = new List<SelectListItem>();
foreach (var item in selectList)
{
item.Selected = (item.Value != null) ? selectedValues.Contains(item.Value) : selectedValues.Contains(item.Text);
newSelectList.Add(item);
}
return newSelectList;
}
}
I have this enum of countries:
public enum Country
{
[Display(Description ="Netherlands", ResourceType = typeof(MyResource))]
Netherlands = 0,
[Display(Description = "Germany", ResourceType = typeof(MyResource))]
Germany = 1,
[Display(Description = "Belgium", ResourceType = typeof(MyResource))]
Belgium = 2,
[Display(Description = "Luxembourg", ResourceType = typeof(MyResource))]
Luxembourg = 3,
[Display(Description = "France", ResourceType = typeof(MyResource))]
France = 4,
[Display(Description = "Spain", ResourceType = typeof(MyResource))]
Spain = 5
}
And this is an extension method to display the enums in a MultiSelectList:
public static MvcHtmlString MultiSelectBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList)
{
return htmlHelper.ListBoxFor(expression, selectList, new { #class = "chzn-select", data_placeholder = Form.MultiSelect });
}
This MultiSelectList has the 'chosen' style. See this site for more info
This all worked fine when I didn't need it to support more languages etc.
How can I make this work with localization?
You can implement a description attribute.
public class LocalizedDescriptionAttributre : DescriptionAttribute
{
private readonly string _resourceKey;
private readonly ResourceManager _resource;
public LocalizedDescriptionAttributre(string resourceKey, Type resourceType)
{
_resource = new ResourceManager(resourceType);
_resourceKey = resourceKey;
}
public override string Description
{
get
{
string displayName = _resource.GetString(_resourceKey);
return string.IsNullOrEmpty(displayName)
? string.Format("[[{0}]]", _resourceKey)
: displayName;
}
}
}
public static class EnumExtensions
{
public static string GetDescription(this Enum enumValue)
{
FieldInfo fi = enumValue.GetType().GetField(enumValue.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(
typeof(DescriptionAttribute),
false);
if (attributes != null &&
attributes.Length > 0)
return attributes[0].Description;
else
return enumValue.ToString();
}
}
Define it like this:
public enum Roles
{
[LocalizedDescription("Administrator", typeof(Resource))]
Administrator,
...
}
And use it like this:
var roles = from RoleType role in Enum.GetValues(typeof(RoleType))
select new
{
Id = (int)role,
Name = role.GetDescription()
};
searchModel.roles = new MultiSelectList(roles, "Id", "Name");
I want to create a generic checkbox list view model and so I got this:
public class ChckboxListViewModel<T>
{
public List<CheckboxViewModel<T>> CheckboxList { get; set; }
public IEnumerable<T> SelectedValues
{
get { return CheckboxList.Where(c => c.IsSelected).Select(c => c.Value); }
}
public ChckboxListViewModel()
{
CheckboxList = new List<CheckboxViewModel<T>>();
}
}
public class CheckboxViewModel<T>
{
public string Label { get; set; }
public T Value { get; set; }
public bool IsSelected { get; set; }
public CheckboxViewModel(string i_Label, T i_Value, bool i_IsSelected)
{
Label = i_Label;
Value = i_Value;
IsSelected = i_IsSelected;
}
}
It is used by a different view model to represent filters of different statuses:
public class FaultListFilters
{
public string SearchKeyword { get; set; }
public ChckboxListViewModel<Fault.eFaultStatus> StatusFilter { get; set; }
public FaultListFilters()
{
SearchKeyword = null;
StatusFilter = new ChckboxListViewModel<Fault.eFaultStatus>();
StatusFilter.CheckboxList.Add(new CheckboxViewModel<Fault.eFaultStatus>(FaultManagementStrings.OpenStatus,Fault.eFaultStatus.Open,true));
StatusFilter.CheckboxList.Add(new CheckboxViewModel<Fault.eFaultStatus>(FaultManagementStrings.InProgressStatus, Fault.eFaultStatus.InProgress, true));
StatusFilter.CheckboxList.Add(new CheckboxViewModel<Fault.eFaultStatus>(FaultManagementStrings.ClosedStatus, Fault.eFaultStatus.Close, false));
}
}
Now I can't find the right way to display the editors or to create an editor template for that kind of a view model because it is Generic.
I don't want o create a separate editor template for ChckboxListViewModel<int> and then another for ChckboxListViewModel<Fault.eFaultStatus> and so on..
Is it even a goose idea to use generics in this case?
Is there another way to represent and display a check-box list in MVC?
I have done the following but the modle is not binding for some reason:
#using (Html.BeginForm("FaultManagement", "Faults", FormMethod.Get, null))
{
for (int i=0 ; i<Model.FaultListFilters.StatusFilter.CheckboxList.Count() ; i++)
{
#Html.HiddenFor(m => m.FaultListFilters.StatusFilter.CheckboxList[i].Value)
#Html.CheckBoxFor(m => m.FaultListFilters.StatusFilter.CheckboxList[i].IsSelected)
#Html.LabelFor(m=> m.FaultListFilters.StatusFilter.CheckboxList[i].IsSelected,Model.FaultListFilters.StatusFilter.CheckboxList[i].Label)
}
<input type="submit" />
}
Is it even a goose idea to use generics in this case?
Don't think it is.
Is there another way to represent and display a check-box list in MVC?
I would write a custom HTML helper:
public static class HtmlExtensions
{
public static IHtmlString CheckboxListFor<TModel>(
this HtmlHelper<TModel> html,
Expression<Func<TModel, IEnumerable<string>>> ex,
IEnumerable<string> possibleValues)
{
var metadata = ModelMetadata.FromLambdaExpression(ex, html.ViewData);
var availableValues = (IEnumerable<string>)metadata.Model;
var name = ExpressionHelper.GetExpressionText(ex);
return html.CheckboxList(name, availableValues, possibleValues);
}
private static IHtmlString CheckboxList(this HtmlHelper html, string name, IEnumerable<string> selectedValues, IEnumerable<string> possibleValues)
{
var result = new StringBuilder();
foreach (string current in possibleValues)
{
var label = new TagBuilder("label");
var sb = new StringBuilder();
var checkbox = new TagBuilder("input");
checkbox.Attributes["type"] = "checkbox";
checkbox.Attributes["name"] = name;
checkbox.Attributes["value"] = current;
var isChecked = selectedValues.Contains(current);
if (isChecked)
{
checkbox.Attributes["checked"] = "checked";
}
sb.Append(checkbox.ToString());
sb.Append(current);
label.InnerHtml = sb.ToString();
result.Append(label);
}
return new HtmlString(result.ToString());
}
}
Then you could have a view model:
public class FaultListFiltersViewModel
{
public IEnumerable<string> SelectedStatusFilters { get; set; }
public IEnumerable<string> AvailableStatusFilters
{
get
{
return new[] { "Label 1", "Label 2", "Label 3" }
}
}
}
and inside the view you could use the helper:
#Html.CheckBoxListFor(x => x.SelectedStatusFilters, Model.AvailableStatusFilters)
Here is another implementation that will better support bootstrap button-group labels (as it requires them to be seperated) and enum type selected values.
public static IHtmlString CheckboxListFor<TModel, TKey>(this HtmlHelper<TModel> helper, Expression<Func<TModel, IEnumerable<TKey>>> ex, Dictionary<TKey, string> i_PossibleOptions, object i_LabelHtmlAttributes)
where TKey : struct, IConvertible
{
var metadata = ModelMetadata.FromLambdaExpression(ex, helper.ViewData);
var selectedValues = (IEnumerable<TKey>)metadata.Model;
var name = ExpressionHelper.GetExpressionText(ex);
return helper.CheckboxList(name, selectedValues, i_PossibleOptions, i_LabelHtmlAttributes);
}
private static IHtmlString CheckboxList<TKey>(this HtmlHelper helper, string name, IEnumerable<TKey> i_SelectedValues, Dictionary<TKey, string> i_PossibleOptions, object i_LabelHtmlAttributes)
where TKey : struct, IConvertible
{
if (!typeof(TKey).IsEnum) throw new ArgumentException("T must be an enumerated type");
var result = new StringBuilder();
foreach (var option in i_PossibleOptions)
{
var label = new TagBuilder("label");
label.MergeAttributes(new RouteValueDictionary(i_LabelHtmlAttributes));
label.Attributes["for"] = string.Format("{0}",option.Key.ToString());
label.InnerHtml = option.Value;
var checkbox = new TagBuilder("input");
checkbox.Attributes["type"] = "checkbox";
checkbox.Attributes["name"] = name;
checkbox.Attributes["id"] = string.Format("{0}", option.Key.ToString());
checkbox.Attributes["value"] = option.Key.ToString();
bool isChecked = ((i_SelectedValues != null) && (i_SelectedValues.Contains(option.Key)));
if ( isChecked )
{
checkbox.Attributes["checked"] = "checked";
}
result.Append(checkbox);
result.Append(label);
}
return new HtmlString(result.ToString());
}
And then the View Model looks like that:
public class FaultListFilters
{
[Display(ResourceType = typeof(FaultManagementStrings), Name = "SearchKeyword")]
public string SearchKeyword { get; set; }
public Dictionary<Fault.eFaultStatus, string> PossibleFaultStatuses
{
get
{
var possibleFaultStatuses = new Dictionary<Fault.eFaultStatus, string>();
possibleFaultStatuses.Add(Fault.eFaultStatus.Open, FaultManagementStrings.OpenStatus);
possibleFaultStatuses.Add(Fault.eFaultStatus.InProgress, FaultManagementStrings.InProgressStatus);
possibleFaultStatuses.Add(Fault.eFaultStatus.Close, FaultManagementStrings.ClosedStatus);
return possibleFaultStatuses;
}
}
public IEnumerable<Fault.eFaultStatus> SelectedFaultStatuses { get; set; }
public FaultListFilters()
{
SearchKeyword = null;
SelectedFaultStatuses = new[] { Fault.eFaultStatus.Open, Fault.eFaultStatus.InProgress };
}
}
and the usage remains the same (except i have added the label html attributes)
<div class="btn-group">
#Html.CheckboxListFor(m => m.FaultListFilters.SelectedFaultStatuses, Model.FaultListFilters.PossibleFaultStatuses, new { Class="btn"})
</div>
I wrote a helper method to display enums from my model in my asp.net MVC application as drop down lists in my views.
Here is my code for that:
public static List<SelectListItem> CreateSelectItemList<TEnum>(object enumObj,
string defaultItemKey,
bool sortAlphabetically,
object firstValueOverride)
where TEnum : struct
{
var values = (from v in (TEnum[])Enum.GetValues(typeof(TEnum))
select new
{
Id = Convert.ToInt32(v),
Name = ResourceHelpers.GetResourceValue(AppConstants.EnumResourceNamespace,
typeof(TEnum).Name, v.ToString())
});
return values.ToSelectList(e => e.Name,
e => e.Id.ToString(),
!string.IsNullOrEmpty(defaultItemKey) ? ResourceHelpers.GetResourceValue(AppConstants.EnumResourceNamespace, defaultItemKey) : string.Empty,
enumObj,
sortAlphabetically,
firstValueOverride);
}
This actually generates the select item list:
public static List<SelectListItem> ToSelectList<T>(
this IEnumerable<T> enumerable,
Func<T, string> text,
Func<T, string> value,
string defaultOption,
object selectedVal,
bool sortAlphabetically,
object FirstValueOverride)
{
int iSelectedVal = -1;
if(selectedVal!=null)
{
try
{
iSelectedVal = Convert.ToInt32(selectedVal);
}
catch
{
}
}
var items = enumerable.Select(f => new SelectListItem()
{
Text = text(f),
Value = value(f),
Selected = (iSelectedVal > -1)? (iSelectedVal.ToString().Equals(value(f))) : false
});
#region Sortare alfabetica
if (sortAlphabetically)
items = items.OrderBy(t => t.Text);
#endregion Sortare alfabetica
var itemsList = items.ToList();
Func<SelectListItem, bool> funct = null;
string sValue = string.Empty;
SelectListItem firstItem = null;
SelectListItem overridenItem = null;
int overridenIndex = 0;
if (FirstValueOverride != null)
{
sValue = FirstValueOverride.ToString();
funct = (t => t.Value == sValue);
overridenItem = itemsList.SingleOrDefault(funct);
overridenIndex = itemsList.IndexOf(overridenItem);
if (overridenItem != null)
{
firstItem = itemsList.ElementAt(0);
itemsList[0] = overridenItem;
itemsList[overridenIndex] = firstItem;
}
}
if(!string.IsNullOrEmpty(defaultOption))
itemsList.Insert(0, new SelectListItem()
{
Text = defaultOption,
Value = "-1"
});
return itemsList;
}
These is the method I call:
public static MvcHtmlString EnumDropDownList<TEnum>(this HtmlHelper htmlHelper,
object enumObj,
string name,
string defaultItemKey,
bool sortAlphabetically,
object firstValueOverride,
object htmlAttributes)
where TEnum : struct
{
return htmlHelper.DropDownList(name,
CreateSelectItemList<TEnum>(enumObj,
defaultItemKey,
sortAlphabetically,
firstValueOverride),
htmlAttributes);
}
Now I am having the problem described here
When I call this helper method and the input's name is the same as the property's name the selected value doesn't get selected.
The alternate solution described there doesn't work for me. The only solution that works is changing the name and not using the model binding using FormCollection instead.
I don't like this workaround because I can't use validation any more using the ViewModel pattern and I have to write some extra code for every enum.
I tried writing a custom model binder to compensate for this somehow but none of the methods I can override there gets called when I start the action.
Is there any way to do this without using FormCollection?
Can I somehow intercept ASP.NET MVC when it tries to put the value into my input field and make it select the right value?
Thank you in advance.
I have a sollution now
Here is the code for the EnumDropDownList function the other functions are listed in the question:
public static MvcHtmlString EnumDropDownList(this HtmlHelper htmlHelper,
object enumObj,
string name,
string defaultItemKey,
bool sortAlphabetically,
object firstValueOverride,
object htmlAttributes)
{
StringBuilder sbRezultat = new StringBuilder();
int selectedIndex = 0;
var selectItemList = new List<SelectListItem>();
if (enumObj != null)
{
selectItemList = CreateSelectItemList(enumObj, defaultItemKey, true, null);
var selectedItem = selectItemList.SingleOrDefault(item => item.Selected);
if (selectedItem != null)
{
selectedIndex = selectItemList.IndexOf(selectedItem);
}
}
var dict = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
TagBuilder tagBuilder = new TagBuilder("select");
tagBuilder.MergeAttribute("name", name,true);
bool bReadOnly = false;
//special case for readonly
if(dict.ContainsKey("readonly"))
{
//remove this tag it won't work the way mvc renders it anyway
dict.Remove("readonly");
bReadOnly = true;
}
//in case the style element is completed if the drop down is not readonly
tagBuilder.MergeAttributes(dict, true);
if (bReadOnly)
{
//add a small javascript to make it readonly and add the lightgrey style
tagBuilder.MergeAttribute("onchange", "this.selectedIndex=" + selectedIndex + ";",true);
tagBuilder.MergeAttribute("style", "background: lightgrey", true);
}
sbRezultat.Append(tagBuilder.ToString(TagRenderMode.StartTag));
foreach (var option in selectItemList)
{
sbRezultat.Append(" <option value='");
sbRezultat.Append(option.Value);
sbRezultat.Append("' ");
if (option.Selected)
sbRezultat.Append("selected");
sbRezultat.Append(" >");
sbRezultat.Append(option.Text);
sbRezultat.Append("</option>");
}
sbRezultat.Append("</select>");
return new MvcHtmlString(sbRezultat.ToString());
}
I also wrote a generic function of type For (EnumDropDownFor):
public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
string defaultItemKey,
bool sortAlphabetically,
object firstValueOverride,
object htmlAttributes)
where TProperty : struct
{
string inputName = GetInputName(expression);
object selectedVal = null;
try
{
selectedVal = htmlHelper.ViewData.Model == null
? default(TProperty)
: expression.Compile()(htmlHelper.ViewData.Model);
}
catch//in caz ca e ceva null sau ceva de genu'
{
}
return EnumDropDownList(htmlHelper,
selectedVal,
inputName,
defaultItemKey,
sortAlphabetically,
firstValueOverride,
htmlAttributes);
}
and some helper methods:
public static string GetInputName<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression)
{
if (expression.Body.NodeType == ExpressionType.Call)
{
MethodCallExpression methodCallExpression = (MethodCallExpression)expression.Body;
string name = GetInputName(methodCallExpression);
return name.Substring(expression.Parameters[0].Name.Length + 1);
}
return expression.Body.ToString().Substring(expression.Parameters[0].Name.Length + 1);
}
private static string GetInputName(MethodCallExpression expression)
{
MethodCallExpression methodCallExpression = expression.Object as MethodCallExpression;
if (methodCallExpression != null)
{
return GetInputName(methodCallExpression);
}
return expression.Object.ToString();
}
I am currently pulling my hair out. I have an ASP.NET MVC web site with two forms, both have radio buttons on them. On the first page (that works), the radio list appears just fine. However, on the second page the radio buttons are not even present in the source code. Here is the code chunk from the first page (BestTimeType is an Enum that I made):
//Back End
[DisplayName("Time:")]
public RadioButtonListViewModel<BestTimeType> BestTimeRadioList { get; set; }
public EvalModel()
{
BestTimeRadioList = new RadioButtonListViewModel<BestTimeType>
{
Id = "BestTime",
SelectedValue = BestTimeType.Afternoon,
ListItems = new List<RadioButtonListItem<BestTimeType>>
{
new RadioButtonListItem<BestTimeType>{Text = "Morning", Value = BestTimeType.Morning},
new RadioButtonListItem<BestTimeType>{Text = "Afternoon", Value = BestTimeType.Afternoon},
new RadioButtonListItem<BestTimeType>{Text = "Evening", Value = BestTimeType.Evening}
}
};
}
// Front End
<div class="grid_1 evalLabel reqField" style="padding-top: 5px;">
<%= Html.LabelFor(model => model.BestTimeRadioList)%>
</div>
<div class="grid_4" style="text-align: center; padding: 5px 0px 10px 0px;">
<%= Html.RadioButtonListFor(model => model.BestTimeRadioList) %>
</div>
Here is the code chunk for the second page:
//Back End
[Required(ErrorMessage = "*")]
[DisplayName("HS Diploma:")]
public RadioButtonListViewModel<bool> HsDiplomaRadioList { get; set; }
public EmploymentModel()
{
HsDiplomaRadioList = new RadioButtonListViewModel<bool>
{
Id = "HsDiploma",
SelectedValue = false,
ListItems = new List<RadioButtonListItem<bool>>
{
new RadioButtonListItem<bool> {Text = "Yes", Value = true},
new RadioButtonListItem<bool> {Text = "No", Value = false}
}
};
}
//Front End
<div class="grid_2 employLabel reqField">
<%= Html.LabelFor(model => model.HsDiplomaRadioList) %>
</div>
<div class="grid_3">
<%= Html.RadioButtonListFor(model => model.HsDiplomaRadioList)%>
<%= Html.ValidationMessageFor(model => model.HsDiplomaRadioList)%>
</div>
I also tried making a custom Enum for the HsDiplomaRadioList (Yes/No), but the radio did not show up either.
I must be missing something extremely stupid simple. If any more code is necessary, I will be glad to put them up.
Thanks in advance.
Edit
Here is the code for RadioButtonList:
public static class HtmlHelperExtensions
{
public static string RadioButtonListFor<TModel, TRadioButtonListValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, RadioButtonListViewModel<TRadioButtonListValue>>> expression) where TModel : class
{
return htmlHelper.RadioButtonListFor(expression, null);
}
public static string RadioButtonListFor<TModel, TRadioButtonListValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, RadioButtonListViewModel<TRadioButtonListValue>>> expression, object htmlAttributes) where TModel : class
{
return htmlHelper.RadioButtonListFor(expression, new RouteValueDictionary(htmlAttributes));
}
public static string RadioButtonListFor<TModel, TRadioButtonListValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, RadioButtonListViewModel<TRadioButtonListValue>>> expression, IDictionary<string, object> htmlAttributes) where TModel : class
{
var inputName = GetInputName(expression);
RadioButtonListViewModel<TRadioButtonListValue> radioButtonList = GetValue(htmlHelper, expression);
if (radioButtonList == null)
return String.Empty;
if (radioButtonList.ListItems == null)
return String.Empty;
var divTag = new TagBuilder("div");
divTag.MergeAttribute("id", inputName);
divTag.MergeAttribute("class", "radio");
foreach (var item in radioButtonList.ListItems)
{
var radioButtonTag = RadioButton(htmlHelper, inputName, new SelectListItem { Text = item.Text, Selected = item.Selected, Value = item.Value.ToString() }, htmlAttributes);
divTag.InnerHtml += radioButtonTag;
}
return string.Concat(divTag, htmlHelper.ValidationMessage(inputName, "*"));
}
public static string GetInputName<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression)
{
if (expression.Body.NodeType == ExpressionType.Call)
{
var methodCallExpression = (MethodCallExpression)expression.Body;
string name = GetInputName(methodCallExpression);
return name.Substring(expression.Parameters[0].Name.Length + 1);
}
return expression.Body.ToString().Substring(expression.Parameters[0].Name.Length + 1);
}
private static string GetInputName(MethodCallExpression expression)
{
// p => p.Foo.Bar().Baz.ToString() => p.Foo OR throw...
var methodCallExpression = expression.Object as MethodCallExpression;
if (methodCallExpression != null)
{
return GetInputName(methodCallExpression);
}
return expression.Object.ToString();
}
public static string RadioButton(this HtmlHelper htmlHelper, string name, SelectListItem listItem,
IDictionary<string, object> htmlAttributes)
{
var inputIdSb = new StringBuilder();
inputIdSb.Append(name)
.Append("_")
.Append(listItem.Value);
var sb = new StringBuilder();
var builder = new TagBuilder("input");
if (listItem.Selected) builder.MergeAttribute("checked", "checked");
builder.MergeAttribute("type", "radio");
builder.MergeAttribute("value", listItem.Value);
builder.MergeAttribute("id", inputIdSb.ToString());
builder.MergeAttribute("name", name + ".SelectedValue");
builder.MergeAttributes(htmlAttributes);
sb.Append(builder.ToString(TagRenderMode.SelfClosing));
sb.Append(RadioButtonLabel(inputIdSb.ToString(), listItem.Text, htmlAttributes));
//sb.Append("<br>");
return sb.ToString();
}
public static string RadioButtonLabel(string inputId, string displayText,
IDictionary<string, object> htmlAttributes)
{
var labelBuilder = new TagBuilder("label");
labelBuilder.MergeAttribute("for", inputId);
labelBuilder.MergeAttributes(htmlAttributes);
labelBuilder.InnerHtml = displayText;
return labelBuilder.ToString(TagRenderMode.Normal);
}
public static TProperty GetValue<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) where TModel : class
{
TModel model = htmlHelper.ViewData.Model;
if (model == null)
{
return default(TProperty);
}
Func<TModel, TProperty> func = expression.Compile();
return func(model);
}
}
Ok finally got around to stack tracing (I should do this first, but I was in a rush last night) and found that for some reason model.HsDiplomaRadio is null. I will need to track down the cause of this.