说明:form里面@Html引导的控件,都有两种形式:
接下来我们只讲第1种使用方式。
除了textbox,还有:
@Html.PasswordFor(m => m.Password)
@Html.TextAreaFor(m => m.Name, new {cols=10, rows=50 })
@Html.HiddenFor(m => m.Name)
另外,label也由HtmlHelper方法生成:
@Html.LabelFor(m => m.Name)但作用不大,以为填充label的是属性名(英文Name),要使用自定义的文字,需要在Model属性上添加:
[Display(Name = "用户名")] public string Name { get; set; }
<label> @Html.RadioButtonFor(m => m.IsMale, true) 男 </label> <label> @Html.RadioButtonFor(m => m.IsMale, false) 女 </label>
第一个参数lambda表达式确定radio的name和id,第二个参数(必填)确定radio的value,注意要和其绑定的类型匹配(不匹配也不报错,差评!)
RadioButton绑定的类型,常常是:
public bool IsMale { get; set; }
<label> @Html.RadioButtonFor(m => m.DayOfWeek, DayOfWeek.Monday) 星期一 </label> <label> @Html.RadioButtonFor(m => m.DayOfWeek, DayOfWeek.Tuesday) 星期二 </label>
public DayOfWeek DayOfWeek { get; set; }
注意页面加载时radio的“默认选中”由以下规则确定:
return View(new Student { IsMale = true });
return View(new Student()); //所以IsMale为false
return View(); //model都为null,IsMale更是为null
public bool? IsMale { get; set; }
@Html.RadioButtonFor(m => m.IsMale, false, new { @checked = true }) 女
生成select表单元素。
和radio一样,需要第二个参数IEnumerable<SelectListItem>指明options:
@Html.DropDownListFor(m => m.DayOfWeek, Model.Options)
可以在Model中指定:
public IEnumerable<SelectListItem> Options { get; set; }
然后在return View(new Student{})中为其赋值:
Options = new List<SelectListItem> { new SelectListItem{ Text = "星期一", Value= DayOfWeek.Monday.ToString(), Disabled = true }, new SelectListItem{ Text = "星期二", Value= DayOfWeek.Tuesday.ToString() , Selected = true}, new SelectListItem{ Text = "星期三", Value= DayOfWeek.Wednesday.ToString() }, new SelectListItem{ Text = "星期天", Value= DayOfWeek.Sunday.ToString()}, }
SelectListItem中的属性:Text/Value/Disabled都一目了然,但Selected的设置优先级不如“作为用户选中值”绑定的DayOfWeek。即:只有在DayOfWeek(可空)为null的时候,这里的Selected才有作用。
另外注意:
更多的时候,(因为“类职责划分”的原因)我们Model中不会放SelectListItem的集合,而是这样:
Options = new List<DayOfWeek> { DayOfWeek.Sunday, DayOfWeek.Monday, DayOfWeek.Tuesday }
ASP.NET MVC早就预见了这种场景,所以提供了SelectList类和它的构造函数:
@Html.DropDownListFor(m => m.DayOfWeek, new SelectList(Model.Options, DayOfWeek.Tuesday, //默认选中 new List<DayOfWeek> { DayOfWeek.Sunday } //disabled项 ))可以将任意集合转化成IEnumerable<SelectListItem>。
实际开发中,Options中存放的更有可能是一个一个的自定义对象,比如:
public IList<Major> Options { get; set; }
public class Major { public int Id { get; set; } public string Name { get; set; }
return View(new Student { Options = new List<Major> { new Major{ Id = 1, Name = "C#"}, new Major{ Id = 2, Name = "SQL"}, new Major{ Id = 3, Name = "ASP.NET"},
但这样的话,下拉列表就变得很怪异:
因为我们还没有指定它的text和value。需要在SelectList中另外两个参数dataValueField和dataTextField:
@Html.DropDownListFor(m => m.SelectedMajor.Id, new SelectList( Model.Options, "Id", "Name" ))
注意其中lambda表达式最后确定的属性,要和dataValueField匹配,或者直接:
@Html.DropDownListFor(m => m.SelectedMajorId,另外,DropDownListFor还可以带一个参数:optionLabel,表示添加一个默认的空选项:
@Html.DropDownListFor(m => m.SelectedMajorId, new SelectList( Model.Options, "Id", "Name" ), "---------")
选中此项,等同于“用户没选”,Model绑定时对应的属性值为null(演示)
生成复选框(input type="checkbox")
@Html.CheckBoxFor(m => m.IsMale)
但是,方法CheckBoxFor()中的参数lamba需要返回值为bool:
public static MvcHtmlString CheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool>> expression);
当checkbox用于多选时,该限制会给我们后台Model的组织带来麻烦。比如,我们需要用户选择“在一周中的哪几天学习”,咋办呢?
@想一想@:这样的写法是不是很傻?
public bool StudyInMonday { get; set; } public bool StudyInTuesday { get; set; } public bool StudyInWednesday { get; set; } //……
更多的时候,我们希望这样一个简单的Model属性:
public IList<DayOfWeek> StudyDays { get; set; }
把用户所选的时间全部放在这个集合中。
Array days = Enum.GetValues(typeof(DayOfWeek)); for (int i = 0; i < days.Length; i++) { <label> <input type="checkbox" name="StudyDays" value="@days.GetValue(i)" /><br /> </label> }
我们在razor view中获取到DayOfWeek的Array,然后遍历,生成7个原生的HTML checkbox。
注意:为了在Action中成功Model绑定,name必须是StudyDays(同Model集合名),value必须是DayOfWeek的枚举值。
演示:Action参数student中正确获得用户选择
#体会#:
那么,
还有啥作用呢?
实际上,我们在开发过程中,很多时候Model的数据是从数据库来的,可选项是一个一个的(自定义)实体类的集合,类似于之前提到的IList<Major>,但是为了用于checkbox需要多加一个bool值:
public class Major { public int Id { get; set; } public bool Selected { get; set; }
这样,在razor view里,就可以这样声明:
for (int i = 0; i < Model.Options.Count; i++) { <label> @Html.CheckBoxFor(m => Model.Options[i].Selected) @Model.Options[i].Name
演示:同时生成了
<input name="Options[0].Selected" type="hidden" value="false">
注意它的name(和checkbox同名)和value(总是为false)
为什么呢?因为只有这样,所有的options才会再次被post到后台。
#理解#:
这样,在Action中,我们就可以遍历Options,既知道哪些option被选中,也知道哪些option没被选中!
for (int i = 0; i < student.Options.Count; i++) { if (student.Options[i].Selected) { } else { } //未被用户选中
演示razor view中使用foreach进行遍历,后台Model绑定失败。
因为生成的HTML标签,name变成了item.Selected,Model中找不到item属性呀(复习:Model绑定规则)
<input id="item_Selected" name="item.Selected" type="checkbox" value="true">
对比for循环的name:Options[0].Selected
<input data-val="true" data-val-required="Selected 字段是必需的。" id="Options_0__Selected" name="Options[0].Selected" type="checkbox" value="true">
PS:
断点演示:其实不光Id,Name也都没值呢!
@想一想@:为什么?因为POST的时候没有Id相关的数据呀。
#体会#:
解决办法:利用hide input……
@Html.HiddenFor(m => Model.Options[i].Id)
利用HtmlHelper(文件上传除外)完成以下页面:
并确保能在后台通过model绑定接收到用户输入。下拉列表所需数据Controller中直接生成即可。
多快好省!前端后端,线上线下,名师精讲
更多了解 加: