最近实在是太忙,客户丢了一个框架,没有任何说明文档,更没有所谓的技术支持,一直忙于学习,最后好歹还有点头绪,话不多说,MVC的学习是不能拉下的,就当前小白的我,认为MVC中的M并不是想象中的那样简单,一般用作前后台的数据交互。
什么是模型?什么是模型绑定?
微软出的《ASP.NET MVC 5编程实战》中有讲到,模型分领域模型、视图模型。个人理解视图模型就是一个数据库对应的实体类。领域模型狭义的来说包括视图模型和一些其他的属性。
视图传递参数+值(或实体对象),Action中接收。看似是一瞬间完成的。中间其实是需要经过两个步骤,①通过实现IValueProvider接口来获取视图中(Form、RouteData、QueryString、HttpFileCollection)请求值。②在通过实现IModelBind中的方法将这些获取的请求参数、值绑定到Action中对应的形参上。同样这里接口中方法都是默认去调用的,如果有需要,可以进行自定义编写实现其接口的方法。
比如,最常见的 将数据库中A表的部分数据显示在视图V中,然后进行增删该查操作。这里在视图V中,最上面会引用 该表的实体类@model 项目名.文件夹.实体类,再根据Razor语法,就可以用Lambda表达式点出来 该表的列名
创建--前台表单数据提交到Controller
@model MVC_plug.Models.Students @{ ViewBag.Title = "Create"; } <h2>Create</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Students</legend> <div class="editor-label"> @Html.LabelFor(model => model.Stu_Name) </div> <div class="editor-field"> @Html.EditorFor(model => model.Stu_Name) @Html.ValidationMessageFor(model => model.Stu_Name) </div>
这里 浏览器解析Razor 语法是 将 BeginForm 解析为From表单,对于HTML来说是,是不存在实体类之说的,表单提交的值仅仅是以键值对的方式进行存储后提交到指定的Action中.也就是将视图中的请求参数与action中的形参进行匹配、绑定。这就是简单模型绑定。
1 .在Controller中对应的Action的方法体中 将 Student 作为参数来接收
[HttpPost] public ActionResult Create(Students students) { if (ModelState.IsValid) { db.Students.Add(students); db.SaveChanges(); return RedirectToAction("Index"); } return View(students); }
既然View中不存在将提交的内容绑定到 实体类中,那么输入的数据为什么在Action的参数Student中可以点出来? 实际上 View 中Post提交的数据 是以键值对的方式进行存储,然后映射到提交的Action中的 Student中,前提是 View中的键名(Name名字)必须要等于 实体类型的属性名,否则无法绑定
2.在Controller中对应的Action的方法体中直接设置参数来接收值 ()
public ActionResult Create(string Stu_Name,string Tel,string phone)
运行项目,其中Stu_Name、Tel 有值,phone 无值,当然这只是佐证,如果在前台的View 中设置的名字不一样,后台用Student去接收,同样也会得到空值。
后台传递数据到前台
1. 显示某数据列表 ,同样是后台Controller 将 查询的结果 赋值给一个实体类对象,用反射也好,反序也行,再 Return View(实体类);
前台最上面要引用 @model 指向实体类 来接收传递的数据,因为是同一个实体,直接映射到前台,最后View 中进行显示即可
2. 当然还可以选择 ViewData 和ViewBag 在后台的Action中赋值,然后在View中接收,关于这两者的比较,这里简单的整理下
ViewData 的 ViewDataDictionary 是一个特殊的字典类,当在控制器中使用 ViewData["CurrentTime"] = DateTime.Now; 其实是将这个值以键值对的形式进行存储
ViewBag不再是字典的键值对结构,而是dynamic动态类型,它会在程序运行的时候动态解析
MVC 高级编程中提高两者的区别
①只有当要访问的关键字是一个有效的C#标识符时,ViewBag 才起作用。
例如,如果在ViewData["Key With Spaces"]中存放一个值,那么就不能使用ViewBag访问。因为这样根本就无法通过编译。
②动态值不能作为一个参数传递给扩展方法。因为C#编译器为了选择正确的扩展方法,在编译时必须知道每一个参数的真正类型。如果其中任何一个参数是动态的,那么就不会通过编译。
例如,这行代码就会编译失败:@Html.TextBox("name",ViewBag.Name)。要使这行代码通过编译有两种方法:第一是使用ViewData["Name"],第二是把ViewBag.Name值转换为一个具体的型:(string)ViewBag.Name 。
说白了,ViewBag 就是在ViewData的升级版,两者只能在Action中起作用,当然,两者的数据是可以相互访问。ViewBag的底层是ViewData,所以当两者定义同一属性不同值的时候,视图中显示的值永远是ViewData所定义的值
// GET: Test public ActionResult Index() { ViewBag.Name = "顓頊viewbag"; ViewData["Name"] = "顓頊viewdata"; return View(); }
前台视图中显示的值,均是 顓頊viewdata
@Html.TextBox("Name",(string)ViewBag.Name) <br/> @Html.TextBox("Name",ViewData["Name"])
此外当用 TextBoxFor +强类型视图时,若在控制器中给实体类赋值,视图中又用New{ Value=“” } 来赋值,则实体对象中的值将被覆盖。
public ActionResult Index() { Test te = new Test(); te.Name = "顓頊"; TestViewModel testViewModel = new TestViewModel() { test = te, Tests = new List<Test>() }; ViewBag.Name = "顓頊viewbag"; ViewData["Name"] = "顓頊viewdata"; return View(testViewModel); }
如下视图均显示颛顼viewdata(Value中首字母V需大写)
@Html.TextBoxFor(m => m.test.Name,new { Value= ViewData["Name"]}) <br /> @Html.TextBoxFor(m => m.test.Name, new { Value = (string)ViewBag.Name })
市人皆大笑,举手揶揄之