在MVC Razor视图中的foreach循环中使用DropDownListFor时出错

时间:2014-06-24 12:17:46

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

我正在尝试在ASP.MVC中创建一个简单的表单,其中显示了引号列表,并允许用户通过从下拉列表中选择一个人来分配该引号来创建工作订单,然后提交表单一气呵成。

我的问题是我在foreach循环中使用DropDownListFor会导致错误,我不认为我会以正确的方式解决这个问题。

(略微简化)引用如下:

public class QuoteItem
{
    public QuoteItem()
    {
        this.IsWorkOrder = false;
    }

    [Key]
    public int QuoteItemCostID { get; set; }
    public string Item { get; set; }
    public decimal? Subtotal { get; set; }
    public bool IsWorkOrder { get; set; }

    [NotMapped]
    public string AssignedTo { get; set; }
}

我的View Model配置如下:

public class UnassignedWorkOrdersViewModel
{
    public IEnumerable<QuoteItemCost> QuoteItemCosts { get; set; }
    public IEnumerable<SelectListItem> Trades { get; set; }
}

一个看起来像这样的控制器动作:

public ActionResult Unassigned(int id = 0)
{

    var trades = db.UserProfiles.Where(u => u.Typpe == "Trade").ToArray().Select(x => new SelectListItem
    {
        Value = x.FirstName + " " + x.LastName,
        Text = x.FirstName + " " + x.LastName
    }).ToList();


    var quoteItems = db.QuoteItems
        .Where(x => x.IsWorkOrder == false)
        .ToList();

    UnassignedWorkOrdersViewModel viewModel = new UnassignedWorkOrdersViewModel
    {
        Trades = trades,
        QuoteItemCosts = quoteItemCosts
    };

    return View(viewModel);
}

我的问题是,在我看来,我试图显示每个工作单和旁边的交易下拉列表,而我认为我这样做的方式是映射class property&#34; AssignedTo&#34;到下拉列表中的值,但这不起作用,因为DropDownList期望LINQ表达式作为第一个参数:

@model Project.ViewModels.UnassignedWorkOrdersViewModel

@if (Model.QuoteItemCosts.Any())
{
    using (Html.BeginForm("Unassigned", "WorkOrder", FormMethod.Post, null))
    {
    @Html.AntiForgeryToken()
    <table>

        @foreach (var item in Model.QuoteItemCosts)
        {

            <tr>
                <td style="width:100px;">
                    <b>Item:</b> @item.Item
                </td>
                <td style="width:200px;">
                    <b>Total:</b> @item.Subtotal
                </td>
                <td>
                    <b>Assign:</b>
                    @Html.DropDownListFor(
                        item.AssignedTo,  // THIS LINE CAUSES AN ERROR 
                        Model.Trades,
                        "", new { @id = "ddlStatus", @style = "width:100%" })
                </td>
            </tr>
        }
    </table>
}

我如何解决这个问题,我是否正确地采取了这种方式?在表单提交上,我应该返回ViewModel,然后返回我的所有QuoteItems,但如果用户从下拉列表中选择了一个人,则返回AssignedTo条目。

编辑:

下面安德烈的建议帮助我并找到了另一个解决方案,我的DropDownListFor现在看起来像这样:

 @Html.DropDownListFor(
                        m => m.QuoteItemCosts.First(q => q.QuoteItemCostID == item.QuoteItemCostID).AssignedTo,
    Model.Trades,
    "", new { @id = "ddlStatus", @style = "width:100%" })

但是当我提交表单时,viewmodel为null:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Unassigned(UnassignedWorkOrdersViewModel viewModel)
    {
        // My viewModel is null
        return RedirectToAction("Index");
    }

我已更新我的剃刀代码以包含Html.BeginForm。

1 个答案:

答案 0 :(得分:3)

为了使一切正确,您需要在此处使用常规for循环:

@for (int i = 0; i < Model.QuoteItemCosts.Count; i++)
{
    <tr>
        <td style="width:100px;">
            <b>Item:</b> @Model.QuoteItemCosts[i].Item
        </td>
        <td style="width:200px;">
            <b>Total:</b> @Model.QuoteItemCosts[i].Subtotal
        </td>
        <td>
            <b>Assign:</b>
            @Html.DropDownListFor(
                m => m.QuoteItemCosts[i].AssignedTo,  // THIS LINE CAUSES AN ERROR 
                Model.Trades,
                "", new { @id = "ddlStatus", @style = "width:100%" })
        </td>
    </tr>
}

现在,您可能会徘徊为什么不保留foreach并使用m => item.AssignedTo。这是ASP.NET MVC视图中foreach循环的一个众所周知的问题。这里的问题是上面的表达式将生成一个带有错误name属性的select标记,并且在发布表单时不会收到它的值。但是,使用常规for循环生成的名称是正确的。