我刚刚开始学习MVC4,我必须承认我对所有依赖lambda表达式,泛型和匿名类型都有一点挑战,特别是当有很多重载函数时。尝试理解HTML帮助程序的工作方式有点令人困惑。以“DropDownListFor”Helper为例。我试图从我的代码中提取基本要素。这就是为什么你在表格中只看到一个列“性别”的原因。希望它在语法上仍然正确:
@model IEnumerable<BusinessLayer.Employee>
<table>
@foreach (var employee in Model)
{
<tr>
<td>
@{
var listItems = new List<SelectListItem>()
{
new SelectListItem {Text = "Male", Value = "M"},
new SelectListItem {Text = "Female", Value = "F"}
};
@Html.DropDownListFor(m => employee.Gender, listItems, listItems.Find(i => i.Value == employee.Gender).Text)
}
</td>
</tr>
}
</table>
Model对象中有两个Employees,一个IEnumerable of Employee,并生成以下HTML
<table>
<tr>
<td>
<select id="employee_Gender" name="employee.Gender"><option value="">Male</option>
<option value="M">Male</option>
<option value="F">Female</option>
</select>
</tr>
</td>
<select id="employee_Gender" name="employee.Gender"><option value="">Female</option>
<option value="M">Male</option>
<option value="F">Female</option>
</select>
</td>
</table>
查看DropDownListFor方法的第一个参数,
@Html.DropDownListFor(m => employee.Gender, ...
...我是否正确理解“m”代表传递给View的模型类的实例?在我看过的在线示例中,我看到过“m”似乎引用模型类但模型是单个实例类的示例,例如,单个Employee对象,而不是Employees的集合。就是这里我要显示Employees的表列表。我假设DropDownListFor方法的第一个参数的意图是“点/绑定”到模型中的属性,这就是我制作m =&gt; employee.Gender的原因。这是当模型是Employees而不是单个Employee的集合时我应该做什么?如果是这样,我对如何为两个下拉列表生成唯一ID感到困惑,这两个下拉列表都为NAME分配了“employee_Gender”和ID属性。
对于Helper DropDownListFor的第3个参数,
listItems.Find(i => i.Value == employee.Gender).Text
这合理吗? employee.Gender的值为“M”或“F”,但显示文本为“男性”和“女性”。我很困惑这个参数是否用于指定默认的“NO SELECT”第一个值,或者该参数是否用于从下拉列表中选择当前Employee的值---或者它可以同时执行这两个值?例如,如果找到,则选择 Text ,如果找不到值,则添加指定为 FIRST?参数的文本?这看起来就像我看到的那样。这个第三个参数可以简化,还是我的例子合理?
感谢您耐心阅读我的许多问题,以便更好地理解这一点。
答案 0 :(得分:25)
你并不孤单。 Lambdas + MVC使编码变得容易,但它们也使它看起来相当神奇(由于抽象)。
查看DropDownListFor方法的第一个参数[...]我是否正确理解“m”表示传递给View的模型类的实例?
是
Raz中的HTML Helpers + Lambdas简单而神奇,因为它们采用了一种捷径,并没有真正向你透露正在发生的事情。首先,我们来看看@Html
。我们知道@
开始我们的Razor语法,然后Html
是神奇的。实际上,Html
是一个HtmlHelper对象,会自动初始化并提供给您。更具体地说,它是HtmlHelper<TModel>
。 Razor HTML编辑器非常智能,并且提前知道TModel将基于您所说的此视图的模型类型的类型。这就是你有这么多intellisense的原因。
键入
时@model IEnumerable<BusinessLayer.Employee>
编辑器会读取该内容并立即假设HTML Helper为HtmlHelper<IEnumerable<BusinessLayer.Employee>>
。当编译页面时,HTML帮助程序实际上就是那种类型(当然)。
那么DropDownListFor
或任何其他扩展方法呢?
查看DropDownListFor我们可以看到它实际上是DropDownListFor<TModel, TProperty>
。我们现在明白TModel是我们视图的模型类型。 DropDownListFor
知道这一点,因为该方法延伸 HtmlHelper<TModel>
。因此DropDownListFor知道传入类型是在视图顶部定义的任何类型。那么TProperty
呢?
TProperty
是返回类型。这是您选择房产时指定的类型。视图为HtmlHelper提供模型类型,然后为模型类型提供DropDownList,现在您在lambda表达式中(x => x.Property)
选择属性,然后为您选择类型;在这种情况下,字符串(性别)。
如果不确切地知道自己要实现的目标,就很难回答你的问题。您是否有一组员工,并且您希望为每个员工显示多个性别下拉框,然后保存它们?
在处理集合时,它有点棘手,因为MVC不能很好地处理它们;通常最好根据您的需要编写自己的解决方案。
我真的不喜欢单个视图在页面上获取内容的想法。考虑一下这条逻辑:
使用MVC会尝试将事情分解为小的逻辑部分。意见应该是愚蠢的;意思是他们不应该真正做任何逻辑或思考。事情变得越来越容易,它确保你的观点不会变成怪物。
试试这个:
在与您正在使用的视图相同的文件夹中创建名为_ EmployeeGender.cshtml 的新PartialView。
使用此代码
<强> _EmployeeGender.cshtml 强>
@model BusinessLayer.Employee
<tr>
<td>
@{
var listItems = new List<SelectListItem>()
{
new SelectListItem {Text = "Male", Value = "M"},
new SelectListItem {Text = "Female", Value = "F"}
};
@Html.DropDownListFor(m => m.Gender, listItems, string.Empty)
}
</td>
</tr>
您的原始观点
@model IEnumerable<BusinessLayer.Employee>
@{
ViewBag.Title = "Employees";
}
<h2>Employees</h2>
<table>
@foreach (var employee in Model)
{
Html.RenderPartial("_EmployeeGender", employee);
}
</table>
现在让我们看一下生成的HTML :
<table>
<tr>
<td>
<select id="Gender" name="Gender"><option value=""></option>
<option selected="selected" value="M">Male</option>
<option value="F">Female</option>
</select>
</td>
</tr><tr>
<td>
<select id="Gender" name="Gender"><option value=""></option>
<option value="M">Male</option>
<option selected="selected" value="F">Female</option>
</select>
</td>
</tr></table>
我们可以看到现在有一个空白的选择,我们的下拉框会自动选择员工的价值观(我创建一名男性和一名女性员工)。
请注意 id
和name
HTML属性相同。如果您想提交包含这些值的表单,则需要更多工作。但这对你来说是一个合理的起点。