0

我需要从动态创建的数据从局部视图传递到控制器从主窗体提交。从部分视图传递收集数据到控制器

下面是返回局部视图的行动:

[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相当陌生,并且仍然在处理这些约定。

回答

0

通过在方法签名中使用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/

https://www.mattlunn.me.uk/blog/2014/08/how-to-dynamically-via-ajax-add-new-items-to-a-bound-list-model-in-asp-mvc-net/

编辑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]值的代码将需要为每个新的项添加到集合被递增。

你如何实现和增加该索引取决于你,但我建议阅读我以前链接到的两篇文章,以了解为什么这是必要的。

+0

我已经试过了。收集仍然是空的。 – Dom

+0

你在HttpGet创建操作中初始化'QuoteItems'集合吗? –

+0

家伙 ​​- 我编辑了我的问题以显示创建操作。 – Dom

相关问题