我们可以为创建和编辑操作提供一个单一的剃刀视图吗?
如果是,我们如何实现这一目标?
我不推荐它。
这应该是一个相当长的答案,因为在正常的 MVC GET/POST 工作流的过程、请求和工作流中涉及到很多事情。我将尝试用所需的最少信息来回答您的问题,以及为什么我不建议使用相同的视图。
首先,为什么?
我建议的方法是使用不同的操作/视图,但共享通用代码:
正常创建两个视图。
您将有重复的代码,但并非所有代码都相同,例如,您可能不想在创建操作上发送 ID,这与您的问题没有直接关系,但使用相同的视图意味着您也在发送相同的数据,不建议这样做,特别是对于过度发布或批量分配。有关此处批量分配的更多信息(我在这里使用的是一种架构方法)。
因此,让我们从您将在控制器中收到的内容开始。在这种情况下,我使用了继承,但这不是唯一的策略。
绑定模型
public class UpdateBindingModel : CreateBindingModel {
// since we are not using the same binding model,
// we can have a "real" validation rules on our update binding and view.
[Required]
public int? Id {get;set;}
}
public class CreateBindingModel {
// no id here prevent overposting.
[Required]
public string Name {get;set;}
[Required]
public int? CountryId {get;set;}
}
这将确保您发送到 Create and Edit 的数据是最少需要的,仅此而已。
然后让我们看看将被发送到视图的视图模型,对于这个例子,我将包含一个列表,它将用于选择一些值,但不应该(列表)发布到控制器,只有选定的值。
查看模型
public class CreateViewModel : CreateBindingModel {
public IEnumerable<SelectListItem> CountryList {get;set;}
}
public class UpdateViewModel : UpdateBindingModel {
public IEnumerable<SelectListItem> CountryList {get;set;}
}
如您所见,这为您提供了很大的灵活性,但仍然有一些重复的代码(两个视图的视图模型所需的额外信息),可以通过多种方式缓解(取决于需求/上下文):
@Html.Action("GetCountryList");
CreateUpdateViewModel
并丢弃视图中的额外UpdateBindingModel
属性,但仍然在 POST 上发布相应的模型。@Html.EditorFor
而不是部分,因此模型绑定器无需额外更改代码即可工作)控制器动作将如下所示:
控制器
[HttpGet]
public ActionResult Create(){
ViewData.Model = new CreateViewModel();
return View();
}
[HttpPost]
public RedirectToRouteResult Create(CreateBindingModel binding) {
// check valid model state and create data
return RedirectToAction("Index");
}
[HttpGet]
public ActionResult Update(int id) {
var objectToEdit = service.GetObjectToEdit(id);
ViewData.Model = new UpdateViewModel(objectToEdit);
return View();
}
[HttpPost]
public RedirectToRouteResult Update(UpdateBindingModel binding) {
// check valid model state and update data
return RedirectToAction("Index");
}
以及您的观点:
意见
Update.cshtml
<form action="Update">
@Html.HiddenFor(Model.Id);
@Html.Partial("EditFieldsPartial")
<button>delete</button> // no delete button on create.
<button>create new</button> // you can have a create new instead of update.
</form>
Create.cshtml
<form action="Create">
@Html.Partial("EditFieldsPartial")
</form>
注意:代码不完整,为了简洁明了,在大多数情况下没有使用帮助程序。不要复制粘贴:D
你当然可以。
在发布时,检查您的控制器是否主键的值为 0,然后插入,否则更新。
创建和编辑的视图应该相同。
只要记住包括:
@Html.HiddenFor(model=>model.ID)
在你看来
例如:
模型:
public class DescriptionModel
{
[Key]
public int ID { get; set; }
public string Description { get; set; }
}
创建编辑.cshtml:
@model DescriptionModel
@using (Html.BeginForm("CreateEdit"))
{
@Html.HiddenFor(model=> model.ID)
@Html.EditorFor(model=> model.Description)
<input type="submit" value='Submit' />
}
描述模型控制器:
public ActionResult Create()
{
return View("CreateEdit", new DescriptionModel());
}
public ActionResult Edit(int id)
{
return View("CreateEdit", db.DescriptionModels.Find(id));
}
// Submit and add or update database
[HttpPost]
public ActionResult CreateEdit(DescriptionModel model)
{
if (ModelState.IsValid)
{
// No id so we add it to database
if (model.ID <= 0)
{
db.DescriptionModels.Add(model);
}
// Has Id, therefore it's in database so we update
else
{
db.Entry(model).State = EntityState.Modified;
}
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
绝对可以使用相同的模型共享视图以进行创建和编辑操作。但是,我强烈建议您三思而后行。在许多情况下,您会希望对编辑操作有不同的视图(例如,隐藏一些不应编辑的输入)以及模型可能略有不同,尽管它可能共享一些(或大部分)值。这些差异会导致视图中出现一些条件,检查您是在创建还是在编辑 - 这可能会使代码混乱。 结论:在决定是否共享视图之前,请先考虑一下编辑屏幕与创建屏幕有多大不同,然后您才能决定。
我不推荐这种方法,但是您可以将主表单从部分加载到两个视图中
你当然可以,但通常这是我会尽量避免的事情。如果创建和编辑操作几乎相同,那么您最终会在控制器中复制大量代码。通常在这种情况下,我的“添加”控制器上只有几个字段,然后在添加项目后,我会将用户重定向到编辑页面,他们可以在其中填写其余信息。
[HttpGet]
public ActionResult myFun(int id = 0)
{
MyClass cls = new MyClass();
if (id == 0)
{
//Insert mode ... no data will be shown to textboxes , when primary key ie. id=0
//Display whole data
}
else
{
//Update mode... if id is not 0 ,data will be shown to textboxes
}
return View(cls);
}
所以,让我们想一想。如果 MVC 规定代码/视图/等是重复的,那么这肯定是一个缺陷吗?作为一名程序员,我永远不想重复任何努力,无论其他任何事情。