首页 新闻 会员 周边

asp.net mvc 如何跨View传值?

0
悬赏园豆:100 [已解决问题] 解决于 2015-12-09 14:14

我模拟的业务场景:内包含多个商品的购物订单的增/删/查/改,我要问的主要是添加(增);

OrderHead Model:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using System.ComponentModel.DataAnnotations;
 6 
 7 namespace Test.Models
 8 {
 9     public class OrderHead
10     {
11         public int Id { get; set; }
12 
13         [Required]
14         [Display(Name = "订单号")]
15         public string OrderNum { get; set; }
16 
17         public virtual ICollection<OrderDetail> OrderDetails { get; set; }
18     }
19 }

OrderDetail Model:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using System.ComponentModel.DataAnnotations;
 6 
 7 namespace Test.Models
 8 {
 9     public class OrderDetail
10     {
11         public int Id { get; set; }
12 
13         [Required]
14         [Display(Name = "商品")]
15         public string Commodity { get; set; }
16 
17         public decimal Qty { get; set; }
18 
19         public decimal Amount { get; set; }
20 
21         //订单内码
22         public int OrderHeadId { get; set; }
23 
24         //订单导航属性
25         public OrderHead OrderHead { get; set; }
26     }
27 }

Order ViewModel:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using FreightOrderTraceability.Models;
 6 using System.Web.Mvc;
 7 
 8 namespace Test.ViewModels
 9 {
10     public class OrderViewModel
11     {
12         public OrderHead OrderHead { get; set; }
13 
14         public OrderDetail OrderDetail { get; set; }
15     }
16 }

CreateOrder Controllers:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Data;
 4 using System.Data.Entity;
 5 using System.Linq;
 6 using System.Net;
 7 using System.Web;
 8 using System.Web.Mvc;
 9 using Test.Models;
10 using Test.ViewModels;
11 
12 namespace Test.Controllers
13 {
14     public class OrdersController : Controller
15     {
16         private DBContext db = new DBContext();
17 
18         // GET: Orders/CreateHead
19         public ActionResult CreateHead()
20         {
21             OrderViewModel createViewModel = new OrderViewModel();
24 return View(createViewModel); 25 } 26 27 [HttpPost] 28 [ValidateAntiForgeryToken] 29 public ActionResult CreateHead(OrderViewModel createViewModel) 30 {
33 if (ModelState.IsValid) 34 { 35 db.OrderHeads.Add(createViewModel.OrderHead); 36 db.SaveChanges(); 37 return RedirectToAction("Index"); 38 } 39 40 return View(createViewModel); 41 } 42 43 // GET: Orders/CreateDetail/5 44 public ActionResult CreateDetail(int? id) 45 { 46 if (id == null) 47 { 48 return new HttpStatusCodeResult(HttpStatusCode.NotFound); 49 } 50 CreateViewModel createViewModel = new CreateViewModel(); 51 createViewModel.OrderHead = db.OrderHeads.Find(id); 52 if (createViewModel.OrderHead == null) 53 { 54 return new HttpStatusCodeResult(HttpStatusCode.NotFound); 55 } 56 return View(createViewModel); 57 } 58 59 [HttpPost] 60 [ValidateAntiForgeryToken] 61 public ActionResult CreateDetail(OrderViewModel createViewModel) 62 { 63 if (ModelState.IsValid) 64 { 65 createViewModel.OrderDetail.OrderHeadId = createViewModel.OrderHead.Id; 66 db.OrderDetails.Add(createViewModel.OrderDetail); 67 db.SaveChanges(); 68 return RedirectToAction("Index"); 69 } 70 return View(createViewModel); 71 } 72 73 protected override void Dispose(bool disposing) 74 { 75 if (disposing) 76 { 77 db.Dispose(); 78 } 79 base.Dispose(disposing); 80 } 81 } 82 }

涉及问题的添加商品明细 CreateDetail View:

 1 @model Test.ViewModels.OrderViewModel
 2 
 3 @{
 4     ViewBag.Title = "添加";
 5     ViewBag.Content = "购物订单明细";
 6     Layout = "~/Views/Shared/_Layout.cshtml";
 7 }
 8 
 9 <h2>@ViewBag.Title</h2>
10 <h4>@ViewBag.Content</h4>
11 <hr />
12 
13 @using (Html.BeginForm())
14 {
15     <dl class="dl-horizontal">
16         <dt>@Html.DisplayNameFor(model => model.OrderHead.OrderNum)</dt>
17         <dd>@Html.DisplayFor(model => model.OrderHead.OrderNum)</dd>
30     </dl>
31     <hr />
32     <div class="row">
33         @Html.AntiForgeryToken()
34         <div class="form-horizontal">
35             @Html.ValidationSummary(true, "", new { @class = "text-danger" })
36             <div class="form-group">
37                 @Html.LabelFor(model => model.OrderDetail.Commodity)
39                 @Html.EditorFor(model => model.OrderDetail.Commodity)
58             </div>
59         </div>
60     </div>
61     <hr />
62     <div class="form-group">
63     <input type="submit" value="保存"/>
65     </div>
66 }

没有使用SPA页面配合jQuery来进行数据库操作,采用MVC原生机制,所以添加一个新的购物订单的操作分为2个页面进行:

1.先添加OrderHead的订单信息:单据号和内码,这个没有问题

2.后添加OrderDetail的商品信息:商品名称、数量、金额并匹配对应的Order的内码,这个有问题;

问题过程:

  1.假设 OrderHead 已保存(自动生成的id=5)

  2.进入 OrderDetail 添加页面(Orders/CreateDetail/5),添加OrderDetail的明细数据,需关联OrderHead的数据(id=5)

  3.进入CreateDetail 添加页面,此时传入的 createViewModel.OrderHead 有值,但等到完成OrderDetail页面的数据(商品、数量、金额)填写后,传回Controllers的ViewModel里createViewModel.OrderHead显示null,createViewModel.OrderDetail有值;

请问:createViewModel.OrderHead的值如何通过ViewModel传入并回传到Controllers?

黄色部分代码执行错误!

注:为简洁,部分冗余无关代码已清楚,请别在意行号;

夕阳寸草畔的主页 夕阳寸草畔 | 初学一级 | 园豆:48
提问于:2015-12-09 13:19
< >
分享
最佳答案
0

都用mvc了。还没有请求响应模型的概念。先弄清楚请求响应的概念就不会有这些乱七八糟的问题了

收获园豆:5
吴瑞祥 | 高人七级 |园豆:29449 | 2015-12-09 13:32
其他回答(2)
1

我来回答下吧。

在这个Action中:

 public ActionResult CreateDetail(int? id)

你构造了 CreateViewModel 的实例,并且初始化了 OrderHead 属性:

 createViewModel.OrderHead = db.OrderHeads.Find(id);

然而,你没有初始化 它的 OrderDetail 属性,这使得在跳转到View页面后,CreateViewModel 的 OrderDetail 属性为null值,自然无法通过 @Html 的扩展方法为 OrderDetail 的下级属性赋值(model => model.OrderDetail.Commodity),然后在提交表单时,OrderDetail  仍保持为 null 传到你的Action方法,这就表现出传值失败。

 

要解决这个问题,需要在CreateDetail(int? id)方法中,初始化CreateView的OrderDetail属性。

收获园豆:95
滴水有灵 | 园豆:297 (菜鸟二级) | 2015-12-09 13:50

但是我实际测试时是回传时 OrderDetail 有值,OrderHead无值.

支持(0) 反对(0) 夕阳寸草畔 | 园豆:48 (初学一级) | 2015-12-09 13:54

目前测试下来的问题在这段:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateDetail(OrderViewModel createViewModel)
         {
             if (ModelState.IsValid)
             {
                 createViewModel.OrderDetail.OrderHeadId = createViewModel.OrderHead.Id;
                 db.OrderDetails.Add(createViewModel.OrderDetail);
                 db.SaveChanges();
                 return RedirectToAction("Index");
             }
             return View(createViewModel);
         }

黄色部分没有值,但是我之前在Get响应时是通过ViewModel明确传入进去的,而且页面上也显示出来了,但是回传时却没了,是不是Get和Post的生命周期是不同的,2个完全独立?

支持(0) 反对(0) 夕阳寸草畔 | 园豆:48 (初学一级) | 2015-12-09 13:58

@夕阳寸草畔: 我看到你的 OrderHeader是一个DisplayNameFor,一个DisplayFor,是不是Display的问题?建议试下EditorFor或者TextBoxFor这两个方法。

 

建议你还是初始化一下 OrderDetail 为好。

2015-12-09 14:04:50 修改:

-----------------------------------------------------------------------------

刚才我看错了,Display是你的本意。

这确实是个奇怪的问题,直觉告诉我不太好找,现在有点忙,回头帮你看看。

支持(0) 反对(0) 滴水有灵 | 园豆:297 (菜鸟二级) | 2015-12-09 13:58

@滴水有灵: 感谢您的提醒!

问题解决了,结合楼上2位的意见,我重新理了下页面生存周期的概念;

在Get的Action里初始化了OrderDetail,并把如下代码放到了Get的Action里:

createViewModel.OrderDetail.OrderHeadId =createViewModel.OrderHead.Id;

其实最关键的一步是在View里添加了:

@Html.HiddenFor(model => model.OrderDetail.OrderHeadId)
其实还是生命周期的概念,没有页面代码承载的话,Get结束,ViewModel也就消失了,到Post时的ViewModel是新生成的。
支持(0) 反对(0) 夕阳寸草畔 | 园豆:48 (初学一级) | 2015-12-09 14:21
0

TempData["Mvc"]="Mvc" TempData也可用于在一次请求中多个Action之间传递数据 

张一辉 | 园豆:208 (菜鸟二级) | 2015-12-15 13:21
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册