首先,您只能使用将强类型视图模型发送回您的视图
return View(model);
View 是基类上的一个方法,而不是用return new View(... 实例化的类
然后是你真正的问题:是的,你可以这样做,但是使用包含不同表单项的顶级 ViewModel 在大多数用例中要容易得多强>。顶级容器 ViewModel 处理得非常好的主要问题是值持久性和服务器端验证以及往返之间的错误消息。
如果您只是担心创建顶级 ViewModel 容器会导致效率低下,请不要担心。这比您可能必须采取的所有解决方法要有效得多,以便在没有顶级 ViewModel 的情况下使行为良好的表单工作。
下面有一些示例代码。下面的代码应该证明使用包含在顶级 ViewModel 中的模型更加简单和整洁:一些表单故意不往返某些状态。请注意HiddenFor 和ModelState.Clear 的用法,它们都与您要执行的操作相关,但即使这些也不会保留inst4.Name 的值以用于Form4Submit。探索的各种选项是:
- 使用查询参数来表示正在发布的表单
- 使用不同的表单名称,但仍使用视图模型。
- 对表单使用仅重定向操作(发送新实例,并且仅发送部分视图模型)
- 混合使用上述方法
public class TestController : Controller
{
//
// GET: /Test/
[System.Web.Mvc.HttpGet]
public ActionResult Index(string msg = null)
{
var model = new MyViewModel
{
Inst1 = new ModelF1 { Name = "Name of F1" },
Inst2 = new ModelF2 (),
InstT = new ModelT {Name = "Name of T"},
PostNumber = 0,
Message = msg
};
return View(model);
}
[System.Web.Mvc.HttpPost]
public ActionResult Index(MyViewModel model, int option = 1)
{
// process models after a form1/2 submit
model.Message = "You posted " +
((option == 1) ? model.Inst1.Name : model.Inst2.Name)
+ " to Index for "
+ ((option == 1) ? "inst1" : "inst2");
model.PostNumber ++;
// This, and the hiddenFor are required to allow us to update the PostNumber each time
ModelState.Clear();
return View(model);
}
[System.Web.Mvc.HttpPost]
public ActionResult Form2Submit(MyViewModel model)
{
// process models after a form2 submit
model.Message = "You posted " + model.Inst2.Name + " to Form2Submit";
model.PostNumber++;
ModelState.Clear();
return View("Index", model);
}
[System.Web.Mvc.HttpPost]
public ActionResult Form3Submit(ModelF3 inst3, ModelT instT)
{
// process models after a form3 submit
var n = instT.Name;
var msg = "You posted " + inst3.Name + ", " + n + " to Form3Submit";
// We no longer have access to pass information back to the view, so lets redirect
return RedirectToAction("Index", new { msg = msg });
}
[System.Web.Mvc.HttpPost]
public ActionResult Form4Submit(ModelF4 inst4, MyViewModel model)
{
// process models after a form4 submit
var n = model.InstT.Name;
model.Message = "You posted " + inst4.Name + ", " + n + " to Form4Submit";
model.PostNumber++;
ModelState.Clear();
return View("Index", model);
}
public class MyViewModel
{
public int PostNumber { get; set; }
public string Message { get; set; }
public ModelF1 Inst1 { get; set; }
public ModelF2 Inst2 { get; set; }
public ModelT InstT { get; set; }
}
public class ModelBase { public string Name { get; set; } }
public class ModelF1 : ModelBase {}
public class ModelF2 : ModelBase { }
public class ModelF3 : ModelBase { }
public class ModelF4 : ModelBase { }
public class ModelT : ModelBase { }
}
那么对于多表单视图:
@using MyWebSite.Controllers;
@model TestController.MyViewModel
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<p>
@Html.Raw(Model.PostNumber) : @Html.Raw(Model.Message)
</p>
<p>
@Html.LabelFor(m => Model.InstT) : <br />
@Html.DisplayFor(m => Model.InstT)
</p>
<div>
<p>Default form submit</p>
@using (Html.BeginForm())
{
<div>
@Html.HiddenFor(m => m.PostNumber)
@Html.LabelFor(m => Model.Inst1.Name)
@Html.TextBoxFor(m => Model.Inst1.Name)
</div>
<input type="submit" value="Submit Index" />
}
</div>
<div>
<p>Use a parameter to denote the form being posted</p>
@using (Html.BeginForm("Index", "Test", new { option = 2 }))
{
<div>
@* Omitting these will not persist them between trips
@Html.HiddenFor(m => Model.Inst1.Name)
@Html.HiddenFor(m => Model.InstT.Name)*@
@Html.HiddenFor(m => m.PostNumber)
@Html.LabelFor(m => Model.Inst2.Name)
@Html.TextBoxFor(m => Model.Inst2.Name)
</div>
<input type="submit" value="Submit with option parameter" />
}
</div>
<div>
<p>Use a different form name, but still use the ViewModel</p>
@using (Html.BeginForm("Form2Submit", "Test"))
{
<div>
@Html.HiddenFor(m => Model.Inst1.Name)
@Html.HiddenFor(m => Model.InstT.Name)
@Html.HiddenFor(m => m.PostNumber)
@Html.LabelFor(m => Model.Inst2.Name)
@Html.TextBoxFor(m => Model.Inst2.Name)
</div>
<input type="submit" value="Submit F2" />
}
</div>
<div>
<p>Submit with a redirect, and no ViewModel usage.</p>
@using (Html.BeginForm("Form3Submit", "Test"))
{
var inst3 = new TestController.ModelF3();
<div>
@Html.HiddenFor(m => Model.InstT.Name)
@Html.LabelFor(m => inst3.Name)
@Html.TextBoxFor(m => inst3.Name)
</div>
<input type="submit" value="Submit F3" />
}
</div>
<div>
<p>Submit with a new class, and the ViewModel as well.</p>
@using (Html.BeginForm("Form4Submit", "Test"))
{
var inst4 = new TestController.ModelF4();
<div>
@Html.HiddenFor(m => Model.Message)
@Html.HiddenFor(m => Model.PostNumber)
@Html.HiddenFor(m => Model.Inst1.Name)
@Html.HiddenFor(m => Model.Inst2.Name)
@Html.HiddenFor(m => Model.InstT.Name)
@Html.LabelFor(m => inst4.Name)
@Html.TextBoxFor(m => inst4.Name)
</div>
<input type="submit" value="Submit F4" />
}
</div>
</body>
</html>