MVC3 - 视图模型复杂类型列表 [英] MVC3 - Viewmodel with list of complex types
问题描述
如果这个道歉已经问;有一百万的方式句话就那么寻找答案已被证明很难。
我有一个视图模型具有以下属性:
公共类AssignSoftwareLicenseViewModel
{
公众诠释LicenseId {搞定;组; }
公众的ICollection< SelectableDeviceViewModel>设备{搞定;组; }
}
SelectableDeviceViewModel的简化版本是这样的:
公共类SelectableDeviceViewModel
{
公众诠释DeviceInstanceId {搞定;组; }
公共BOOL IsSelected {搞定;组; }
公共字符串名称{;组; }
}
在我看来,我试图以显示设备的属性可编辑复选框列表,输入表单中。
目前,我的看法是这样的:
@using(Html.BeginForm())
{
@ Html.HiddenFor(X => Model.LicenseId)
<表>
&所述; TR>
<第i个姓名和LT; /第i
百分位>< /第i
< / TR>
@foreach(在Model.Devices SelectableDeviceViewModel设备)
{
@ Html.HiddenFor(X => device.DeviceInstanceId)
&所述; TR>
< TD> @ Html.CheckBoxFor(X => device.IsSelected)LT; / TD>
< TD> @ device.Name< / TD>
< / TR>
}
< /表> <输入类型=提交值=分配/>
}
问题是,当模型被调回控制器,设备为null。
我的假设是,这种情况正在发生,因为即使我编辑的内容,该设备的属性从未明确地包含在表单中。我试着包括它HiddenFor,但只是导致有一个空列表而不是空的模式。
任何想法,我在做什么错在这里?
我的假设是,这种情况正在发生,因为即使我
编辑其内容的设备属性是从未明确
包括在形式
块引用>没有,你的假设是错误的。这并没有得到正确绑定的原因是因为你的输入字段没有正确的名称。例如,他们被称为
NAME =IsSelected
而不是NAME =设备[0] .IsSelected
。看看正确的线格式,需要使用绑定到集合:<一href=\"http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx\">http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
但是,为什么出现这种情况?
块引用>这是因为您在视图中使用的
的foreach
循环。你用X =&GT; device.IsSelected
为lambda前pression的复选框,但这并不考虑设备的属性在所有(你可以通过查看生成的源$ C $ C看到你网页)。
那么,应该怎么办?
块引用>我个人使用编辑模板,因为他们尊重复杂属性的导航上下文,并产生正确的输入名称推荐你。因此,获得在你看来摆脱了整个
的foreach
循环,用code一行替换为:@ Html.EditorFor(X =&GT; x.Devices)
和现在定义将自动ASP.NET MVC的设备集合中的每个元素呈现一个自定义编辑器模板。警告:此模板的位置和名称都为这个非常重要的工作原理是约定:
〜/查看/共享/ EditorTemplates / SelectableDeviceViewModel.cshtml
:@model SelectableDeviceViewModel
@ Html.HiddenFor(X =&GT; x.DeviceInstanceId)
&所述; TR&GT;
&LT; TD&GT; @ Html.CheckBoxFor(X =&GT; x.IsSelected)LT; / TD&GT;
&LT; TD&GT; @ Html.DisplayFor(X =&GT; x.Name)LT; / TD&GT;
&LT; / TR&GT;另一种方法(我不建议)是改变你目前的
的ICollection
在您的视图模式向的索引的集合(如一个的IList&LT; T&GT;
或数组T []
)公共类AssignSoftwareLicenseViewModel
{
公众诠释LicenseId {搞定;组; }
公众的IList&LT; SelectableDeviceViewModel&GT;设备{搞定;组; }
}然后,而不是在foreach使用
为
循环:@for(VAR I = 0; I&LT; Model.Devices.Count;我++)
{
@ Html.HiddenFor(X =&GT; x.Devices [I] .DeviceInstanceId)
&所述; TR&GT;
&LT; TD&GT; @ Html.CheckBoxFor(X =&GT; x.Devices [I] .IsSelected)LT; / TD&GT;
&LT; TD&GT; @ Html.DisplayFor(X =&GT; x.Devices [I] .Name点&LT; / TD&GT;
&LT; / TR&GT;
}Apologies if this has been asked before; there are a million ways to phrase it so searching for an answer has proved difficult.
I have a viewmodel with the following properties:
public class AssignSoftwareLicenseViewModel { public int LicenseId { get; set; } public ICollection<SelectableDeviceViewModel> Devices { get; set; } }
A simplified version of SelectableDeviceViewModel would be this:
public class SelectableDeviceViewModel { public int DeviceInstanceId { get; set; } public bool IsSelected { get; set; } public string Name { get; set; } }
In my View, I am attempting to display a list of editable checkboxes for the Devices property, inside an input form. Currently, my View looks like this:
@using (Html.BeginForm()) { @Html.HiddenFor(x => Model.LicenseId) <table> <tr> <th>Name</th> <th></th> </tr> @foreach (SelectableDeviceViewModel device in Model.Devices) { @Html.HiddenFor(x => device.DeviceInstanceId) <tr> <td>@Html.CheckBoxFor(x => device.IsSelected)</td> <td>@device.Name</td> </tr> } </table> <input type="submit" value="Assign" /> }
The problem is, when the model gets posted back to the controller, Devices is null.
My assumption is that this is happening because even though I'm editing its contents, the Devices property is never explicitly included in the form. I tried including it with HiddenFor, but that just resulted in the model having an empty list instead of null.
Any idea what I'm doing wrong here?
解决方案My assumption is that this is happening because even though I'm editing its contents, the Devices property is never explicitly included in the form.
No, your assumption is wrong. The reason this doesn't get bound properly is because your input fields doesn't have correct names. For example they are called
name="IsSelected"
instead ofname="Devices[0].IsSelected"
. Take a look at the correct wire format that needs to be used to bind to collections: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspxBut why this happens?
It happens because of the
foreach
loop that you used in your view. You usedx => device.IsSelected
as lambda expression for the checkbox but this doesn't take into account the Devices property at all (as you can see by looking at the generated source code of your web page).So what should I do?
Personally I would recommend you using editor templates as they respect the navigational context of complex properties and generate correct input names. So get rid of the entire
foreach
loop in your view and replace it with a single line of code:@Html.EditorFor(x => x.Devices)
and now define a custom editor template that will automatically be rendered by ASP.NET MVC for each element of the Devices collection. Warning: the location and name of this template are very important as this works by convention:
~/Views/Shared/EditorTemplates/SelectableDeviceViewModel.cshtml
:@model SelectableDeviceViewModel @Html.HiddenFor(x => x.DeviceInstanceId) <tr> <td>@Html.CheckBoxFor(x => x.IsSelected)</td> <td>@Html.DisplayFor(x => x.Name)</td> </tr>
Another approach (which I don't recommend) is to change your current
ICollection
in your view model to an indexed collection (such as anIList<T>
or an arrayT[]
):public class AssignSoftwareLicenseViewModel { public int LicenseId { get; set; } public IList<SelectableDeviceViewModel> Devices { get; set; } }
and then instead of the foreach use a
for
loop:@for (var i = 0; i < Model.Devices.Count; i++) { @Html.HiddenFor(x => x.Devices[i].DeviceInstanceId) <tr> <td>@Html.CheckBoxFor(x => x.Devices[i].IsSelected)</td> <td>@Html.DisplayFor(x => x.Devices[i].Name</td> </tr> }
这篇关于MVC3 - 视图模型复杂类型列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!