从部分视图传递收集数据到控制器
问题描述:
我需要从动态创建的数据从局部视图传递到控制器从主窗体提交。从部分视图传递收集数据到控制器
下面是返回局部视图的行动:
[HttpGet]
public virtual PartialViewResult AddItem()
{
var item = new QuotedItem();
ViewBag.StockID = new SelectList(db.StockItems.OrderBy(s => s.Name), "StockID", "Name");
return PartialView("EditorTemplates/QuotedItem", item);
}
下面是QuotedItem的EditorTemplate:
@model StockSystem.Models.QuotedItem
<div id="itemRow">
<span>
@Html.DropDownListFor(model => model.StockID, null)
@Html.ValidationMessageFor(model => model.StockID, "", new { @class = "text-danger" })
</span>
<span>
@Html.EditorFor(model => model.Price)
@Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" })
</span>
<span>
@Html.EditorFor(model => model.Quantity)
@Html.ValidationMessageFor(model => model.Quantity, "", new { @class = "text-danger" })
</span>
<a href="#" class="deleteSmall"></a>
</div>
这里的景观:
@model StockSystem.Models.Quote
@{
ViewBag.Title = "Create";
}
<h2>New Quote for @ViewBag.Customer</h2>
<hr />
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.Hidden("CustomerID", (object)ViewBag.CustomerID)
<div class="addItem">
@Ajax.ActionLink(" ", "AddItem",
new AjaxOptions
{
UpdateTargetId = "editorRows",
InsertionMode = InsertionMode.InsertAfter,
HttpMethod = "GET"
})
</div>
<div id="editorRows">
@Html.EditorFor(q => q.QuotedItems)
</div>
<p></p>
<div>
<input class="add" type="submit" value="" />
<a class="back" href="@Url.Action("Index", "Quotes", new { id = ViewBag.CustomerID })"></a>
</div>
}
这里的创建操作:
public ActionResult Create(int id)
{
var customer = db.Customers.Find(id);
ViewBag.CustomerID = id;
ViewBag.Customer = customer.CustomerName;
var quote = new Quote() { QuotedItems = new List<QuotedItem>() };
return View(quote);
}
下面是QuotedItem的EF模型:
public partial class QuotedItem
{
public int QuotedItemID { get; set; }
public int QuoteID { get; set; }
public int StockID { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
public virtual Quote Quote { get; set; }
public virtual StockItem StockItem { get; set; }
}
和报价:
public partial class Quote
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Quote()
{
this.QuotedItems = new HashSet<QuotedItem>();
}
public int QuoteID { get; set; }
public int CustomerID { get; set; }
public int UserID { get; set; }
public System.DateTime QuoteDate { get; set; }
public string QuoteRef { get; set; }
public virtual Customer Customer { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<QuotedItem> QuotedItems { get; set; }
public virtual User User { get; set; }
}
我可以将项目添加到页面,但没有将它们添加到提交报价。
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "QuoteID,CustomerID,UserID,QuoteDate,QuoteRef,QuotedItems")] Quote quote) //, List<QuotedItem> items
{
if (ModelState.IsValid)
{
//quote.QuotedItems is empty, how do I bind this data and save to database?
db.Quotes.Add(quote);
db.SaveChanges();
return RedirectToAction("Index", new { id = quote.CustomerID });
}
return View(quote);
}
集合没有被发送到控制器。这是如何完成的?
感谢
编辑:我在想尝试这样的:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "QuoteID,CustomerID,UserID,QuoteDate,QuoteRef,QuotedItems")] Quote quote, List<QuotedItem> items)
{
if (ModelState.IsValid)
{
quote.QuotedItems = items;
db.Quotes.Add(quote);
db.SaveChanges();
return RedirectToAction("Index", new { id = quote.CustomerID });
}
return View(quote);
}
但我认为必须有一个更好的办法。如果我尝试了这种方法,我仍然不完全确定如何将它发送给控制器,我假定它是Html.BeginForm()中的一个参数?我对MVC相当陌生,并且仍然在处理这些约定。
答
通过在方法签名中使用Bind属性,可以防止QuotedItems
属性过帐到控制器操作。
public ActionResult Create([Bind(Include = "QuoteID,CustomerID,UserID,QuoteDate,QuoteRef")] Quote quote)
添加QuotedItems
属性名称包括列表中应该解决这个问题:
public ActionResult Create([Bind(Include = "QuoteID,CustomerID,UserID,QuoteDate,QuoteRef,QuotedItems")] Quote quote)
编辑
没有看到你的QuotedItem编辑模板,这是很难肯定地说,但它听起来像你的问题可能是,每个项目添加到您的列表没有一个唯一的ID组成该项目的元素设置。如果没有这个,模型联编程序将很难确定哪个元素属于集合中的哪个对象。
看看这两篇文章,看看他们是否有帮助:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/
编辑2
模板中的每个元素应该被赋予一个唯一的ID ,索引是做这件事的好方法,项目GUID也是(如果有的话);但只要每个元素ID对该项目都是唯一的,就应该可以工作。
@model StockSystem.Models.QuotedItem
<div id="itemRow">
<span>
@Html.DropDownListFor(model => model.StockID, null)
@Html.ValidationMessageFor(model => model.StockID, "", new { @class = "text-danger" })
</span>
<span>
@Html.EditorFor(model => model.Price, new { htmlAttributes = new { id = $"[{YOURINDEX}].Price" } })
@Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" })
</span>
<span>
@Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { id = $"[{YOURINDEX}].Quantity" } })
@Html.ValidationMessageFor(model => model.Quantity, "", new { @class = "text-danger" })
</span>
<a href="#" class="deleteSmall"></a>
在上述[YOURINDEX]
值的代码将需要为每个新的项添加到集合被递增。
你如何实现和增加该索引取决于你,但我建议阅读我以前链接到的两篇文章,以了解为什么这是必要的。
我已经试过了。收集仍然是空的。 – Dom
你在HttpGet创建操作中初始化'QuoteItems'集合吗? –
家伙 - 我编辑了我的问题以显示创建操作。 – Dom