【问题标题】:Trying to add a ICollection to a ViewModel in ASP.NET尝试将 ICollection 添加到 ASP.NET 中的 ViewModel
【发布时间】:2015-12-30 12:51:40
【问题描述】:

我看过this post,那里的小伙子似乎想做我的目标。我继承了这个应用程序,虽然我是一名 .NET 开发人员,但与我更喜欢的其他语言的其他 MVC 框架相比,MVC 的东西似乎很神奇。我的显着代码如下:

public class PurchaseOrderViewModel
{
    public PurchaseOrderViewModel()
    {
        this.PurchaseOrder = new PurchaseOrder();
    }
    // Some other fields here....
    public PurchaseOrder PurchaseOrder { get; set; }

    public IList<PurchaseOrderItem> OrderItems { get; set; }
 }

控制器:

    [HttpPost]
    public ActionResult Details(PurchaseOrderViewModel viewModel)
    {
       // bunch of stuff. the viewModels.OrderItems here is null. 
    }

模型中的 OrderItems 是一个 ICollection 我将其转换为 IList 以实现迭代。视图的相关部分如下:

 @model PurchaseOrderViewModel
 @for (var i = 0; i < this.Model.OrderItems.Count; i++)
 {                
    @Html.EditorFor(m => m.OrderItems[i].Quantity);
 }

那么,为什么我没有通过 OrderItems?这与它们是 IList 而不是 ICollection 的事实有关吗?如果是这样,解决方法是什么?

编辑: 我已经更改了视图代码,因为我留下了我之前尝试过的东西。

编辑 2: 我考虑了当前的评论/答案,所以现在我做了以下更改:

视图模型:

    public ICollection<PurchaseOrderItem> PurchaseOrderItems { get; set; }

PurchaseOrderItem.cshtml:(为了以防万一,我实际上已将其保留在代码中):

@model Downland.Model.PurchaseOrderItem

<tr style="background-color: #fff; padding: 8px;">
<td style="text-align: left; width: 210px;">
    @if (this.Model.ProductID == null)
    {
        <img class="viewproduct" src="~/Images/GetThumbnail/-1" alt="Product Image" style="padding: 8px;" />
    }
    else
    {
        <img class="viewproduct" src="~/Images/GetProductImage?productId=@(this.Model.ProductID)" alt="Product Image" style="padding: 8px;" />
    }
</td>
<td>
    @(string.IsNullOrEmpty(this.Model.SKU) ? this.Model.NonDownlandSKU : this.Model.SKU)
</td>
<td>@this.Model.ProductName</td>
<td>
    @this.Model.Quantity
    @Html.EditorFor(m => m.Quantity)
</td>
<td>
    @string.Format("{0:C}", this.Model.PriceExVAT)
    @Html.EditorFor(m => m.PriceExVAT)
</td>
<td>@string.Format("{0:C}", this.Model.VATTotal)</td>
<td>
    @string.Format("{0:C}", this.Model.ItemTotal)
</td>
</tr>

查看代码:

@Html.EditorFor(m => m.PurchaseOrderItems);

只是另一个有趣的点。在 GET 上,我根据数据库数据在视图模型中设置 PurchaseOrder 和 PurchaseOrderItems。在 Post 上,我们似乎再次使用数据库中的数据在视图模型中设置 purchaseOrder。根据传递给帖子的内容,视图模型中还有一些其他字段正在正确设置,但 PurchaseOrderItems 仍然为空。

【问题讨论】:

标签: c# asp.net asp.net-mvc


【解决方案1】:

您不应该在视图中进行此转换,因为以下表达式太复杂且不受标准编辑器模板的支持:

m => m.PurchaseOrder.PurchaseOrderItems.ToList()[i].Quantity

因此,您显然应该使用真实的视图模型,在该模型中,您不只是将 EF 对象作为属性填充并使用 ViewModel 后缀命名它(这就是 PurchaseOrderViewModel 的样子)。所以一旦你有了一个真实的视图模型,你就可以很容易地访问相应的属性,因为它的类型是IList&lt;T&gt;

@Html.EditorFor(m => m.PurchaseOrder.PurchaseOrderItems[i].Quantity);

话虽如此,如果由于某种原因您继承了一些类似的遗留垃圾,那么您仍然有一个解决方法。您可以使用编辑器模板。

因此,您首先在~/Shared/EditorTemplates/PurchaseOrderItem.cshtml 中添加以下模板:

@model PurchaseOrderItem
@Html.EditorFor(x => x.Quantity)

此模板的名称非常重要,因为它都是按约定工作的。它应该命名为您拥有并位于~/Shared/EditorTemplates 中的ICollection&lt;&gt; 的类型。

然后像这样简单地调整您的视图:

@Html.EditorFor(m => m.PurchaseOrder.PurchaseOrderItems);

在这种情况下,EditorFor 助手会推断出PurchaseOrderItemsICollection&lt;T&gt;,它会自动循环遍历此集合的元素并呈现您可以自定义的相应~/Shared/EditorTemplates/T.cshtml 模板。


更新:

看来我需要发布一个简单的示例来说明如何使用编辑器模板。

一如既往,让我们从视图模型开始:

public class PurchaseOrderViewModel
{
    public ICollection<PurchaseOrderItem> PurchaseOrderItems { get; set; }
}

public class PurchaseOrderItem
{
    public int Quantity { get; set; }
}

然后是一个具有 2 个动作的控制器(一个用于显示表单,一个用于处理来自该表单的提交数据):

public ActionResult Index()
{
    var model = new PurchaseOrderViewModel();
    // This information will probably come from querying some data store. 
    // That could be a SQL database for example. But for the purpose
    // of this sample we are just hardcoding some values to illustrate 
    // the concept without any dependencies
    model.PurchaseOrderItems = new[]
    {
        new PurchaseOrderItem
        {
            Quantity = 5,
        }
    };
    return View(model);
}

[HttpPost]
public ActionResult Index(PurchaseOrderViewModel model)
{
    // ... everything gets bound correctly here
}

然后是强类型视图:

@model PurchaseOrderViewModel
@using (Html.BeginForm())
{
    @Html.EditorFor(x => x.PurchaseOrderItems)
    <input type="submit" value="OK" />
}

最后是相应的编辑器模板(~/Shared/EditorTemapltes/PurchaseOrderItem.cshtml):

@model PurchaseOrderItem
@Html.EditorFor(x => x.Quantity)

【讨论】:

  • 对不起,误导性的代码。我现在把它改成了其他不起作用的东西,更像是我想要结束的代码。
  • 您已经更改了您的问题,但不幸的是,在这个问题中您展示了一些名为 PurchaseOrderViewModel 的模型,它没有任何集合属性。然而,在您看来,您似乎正在使用一些@Html.EditorFor(m =&gt; m.OrderItems[i].Quantity); 调用,但我在您的视图模型中的任何地方都看不到名为OrderItems 的属性。但在所有情况下,您都应该真正遵循我的建议并使用编辑器模板。只需为OrderItem 类定义一个编辑器模板,然后您甚至不需要在视图中编写for 循环,而是@Html.EditorFor(x =&gt; x.OrderItems)
  • 已更新。抱歉,我试图不让不相关的代码超载,但我真的应该仔细检查我发布的内容。道歉
  • 尝试缩小您的问题范围。消除所有的噪音,然后废话。只是一个简单的 ASP.NET MVC 应用程序,其视图模型包含简单的属性。
  • 请查看我的更新答案以了解我的意思。一旦你有这个非常简单的 ASP.NET MVC 应用程序工作,你可以添加其他废话:附加属性,CSS,数据库访问,EF,...
猜你喜欢
  • 2015-10-06
  • 1970-01-01
  • 2011-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-12
  • 2014-08-29
  • 2014-10-26
相关资源
最近更新 更多