这是一个很难解释的问题,所以我会试着指点。
问题:
我发现了什么:
只有在Razor代码中使用HTML Helpers时才会发生这种情况。
如果我使用传统的<input>
元素(不理想),它可以正常工作。
问题:
以前有没有人遇到过这个问题?或者有人知道为什么会这样,或者我做错了什么?
请查看下面的代码并感谢您查看我的问题!
控制器:
[HttpGet]
public ActionResult Index()
{
List<Car> cars = new List<Car>
{
new Car { ID = 1, Make = "BMW 1", Model = "325" },
new Car { ID = 2, Make = "Land Rover 2", Model = "Range Rover" },
new Car { ID = 3, Make = "Audi 3", Model = "A3" },
new Car { ID = 4, Make = "Honda 4", Model = "Civic" }
};
CarModel model = new CarModel();
model.Cars = cars;
return View(model);
}
[HttpPost]
public ActionResult Index(CarModel model)
{
// This is for debugging purposes only
List<Car> savedCars = model.Cars;
return View(model);
}
Index.cshtml:
如您所见,我有“制作”和“实际制作”输入。一个是HTML助手,另一个是传统的HTML输入。
@using (Html.BeginForm())
{
<div class="col-md-4">
@for (int i = 0; i < Model.Cars.Count; i++)
{
<div id="car-row-@i" class="form-group row">
<br />
<hr />
<label class="control-label">Make (@i)</label>
@Html.TextBoxFor(m => m.Cars[i].Make, new { @id = "car-make-" + i, @class = "form-control" })
<label class="control-label">Actual Make</label>
<input class="form-control" id="car-make-@i" name="Cars[@i].Make" type="text" value="@Model.Cars[i].Make" />
<div>
<input type="hidden" name="Cars.Index" value="@i" />
</div>
<br />
<button id="delete-btn-@i" type="button" class="btn btn-sm btn-danger" onclick="DeleteCarRow(@i)">Delete Entry</button>
</div>
}
<div class="form-group">
<input type="submit" class="btn btn-sm btn-success" value="Submit" />
</div>
</div>
}
Javascript删除功能
function DeleteCarRow(id) {
$("#car-row-" + id).remove();
}
用户界面发生了什么:
答案 0 :(得分:5)
此行为的原因是HtmlHelper
方法使用ModelState
中的值(如果存在)来设置value
属性而不是实际模型值。 TextBoxFor displaying initial value, not the value updated from code的答案解释了这种行为的原因。
在您的情况下,提交时,会将以下值添加到ModelState
Cars[1].Make: Land Rover 2
Cars[2].Make: Audi 3
Cars[3].Make: Honda 4
请注意,Cars[0].Make
没有值,因为您删除了视图中的第一项。
当您返回视图时,该集合现在包含
Cars[0].Make: Land Rover 2
Cars[1].Make: Audi 3
Cars[2].Make: Honda 4
因此,在循环的第一次迭代中,TextBoxFor()
方法检查ModelState
是否匹配,找不到,并生成value="Land Rover 2"
(即模型值)和您的手册输入还读取模型值并设置value="Land Rover 2"
在第二次迭代中,TextBoxFor()
确实在Cars[1]Make
中找到ModelState
的匹配项,因此设置value="Land Rover 2"
并且手动输入读取模型值并设置{{1} }}
我假设这个问题只是为了解释行为(实际上,你会保存数据,然后重定向到GET方法以显示新列表),但是当你返回视图时可以生成正确的输出通过调用value="Audi 3"
来清除所有ModelState.Clear()
值,以便ModelState
根据模型值生成TextBoxFor()
属性。
附注:您的视图包含许多不良做法,包括使用行为污染您的标记(使用Unobtrusive JavaScript),创建不符合标签的标签元素(点击它们不会将焦点设置为关联控制),不必要地使用value
元素(使用css来设置带边距的元素等)以及不必要地使用<br/>
。循环中的代码可以是
new { @id = "car-make-" + i }