在索引视图中内联编辑项目会抛出模型绑定。如何使它工作?

时间:2018-02-22 08:53:21

标签: c# razor asp.net-core-mvc entity-framework-core model-binding

我正在尝试建立一个系统,用户可以点击列表中的某个项目,然后在仍然保留在Index - 视图中时修改该项目。

我的尝试只是Index.cshtml和Edit.cshtml之间的混合:

@model IEnumerable<MyStore.Models.ProductIdentifier>
@{int primary_id = (this.ViewContext.RouteData.Values["primary_id"] != null
        ? int.Parse(this.ViewContext.RouteData.Values["primary_id"].ToString())
        : 0);
}
@foreach (var item in Model)
{
    if (item.Id == primary_id)
    {
        // This list-item is editable (copied from Edit.cshtml):
        <form asp-action="Edit">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="@item.Id" />
            <div class="form-group col-lg-4">
                <input asp-for="@item.Label" class="form-control" />
                <span asp-validation-for="@item.Label" class="text-danger"></span>
            </div>
            <div class="form-group col-lg-6">
                <input asp-for="@item.Description" class="form-control" />
                <span asp-validation-for="@item.Description" class="text-danger"></span>
            </div>
            <div class="form-group col-lg-1">
                <input asp-for="@item.SortOrder" class="form-control" />
                <span asp-validation-for="@item.SortOrder" class="text-danger"></span>
            </div>
            <div class="form-group col-lg-1">
                <button type="submit" value="Save" class="btn btn-primary">
                    <span class="glyphicon glyphicon-floppy-disk"></span> Save
                </button>
            </div>
        </form>
    }
    else
    {
        // This list-item is just a plain list-item:
        <div class="row table">
            <div class="col-lg-4">
                <a asp-action="Index" asp-route-primary_id="@item.Id">
                    @Html.DisplayFor(modelItem => item.Label)
                </a>
            </div>
            <div class="col-lg-6">
                @Html.DisplayFor(modelItem => item.Description)
            </div>
            <div class="col-lg-1">
                @Html.DisplayFor(modelItem => item.SortOrder)
            </div>
            <div class="col-lg-1">
                <a asp-action="Delete" asp-route-id="@item.Id" class="btn btn-xs btn-danger">
                    <span class="glyphicon glyphicon-trash"></span>
                </a>
            </div>
        </div>
    }
}

表单数据应该发布到控制器中的Edit方法:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Label,Description,SortOrder")] ProductIdentifier productIdentifier)
{
    if (id != productIdentifier.Id) { return NotFound(); }
    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(productIdentifier);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!ProductIdentifierExists(productIdentifier.Id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction(nameof(Index));
    }
    return View(productIdentifier);
}

...但是因为我必须在表单中的元素前面添加@item.(因为模型是IEnumerable,而我只想发布单个对象),模型绑定不再有效,并且正在发布null对象。

我怎样才能让它发挥作用?

1 个答案:

答案 0 :(得分:0)

我做到了!

首先,我创建了一个ViewModel,它包含ICollection个标识符和一个标识符实例:

public class ViewModelEditIdentifierInIndexView
{
    public ViewModelProductIdentifier SingleItem { get; set; }
    public ICollection<ViewModelProductIdentifier> ListOfItems { get; set; }
}

我必须在控制器中对Index方法进行一些更改,以满足viewmodel:

public async Task<IActionResult> Index(int? primary_id)
    {
        ProductIdentifier pi = await _context.ProductIdentifiers
                                .Where(i => i.Id == primary_id)
                                .SingleOrDefaultAsync();
        ViewModelEditIdentifierInIndexView ViewModel = new ViewModelEditIdentifierInIndexView
        {
            SingleItem = _mapper.Map<ViewModelProductIdentifier>(pi),
            ListOfItems = _mapper.Map<ICollection<ViewModelProductIdentifier>>(await _context.ProductIdentifiers.ToListAsync())
        };
        return View(ViewModel);
    }

然后,我在索引视图中更改了模型:

@model MyStore.Models.ViewModels.ViewModelEditIdentifierInIndexView

然后,我改变了编辑表格。最重要的变化是在每个name字段中添加input - 标记:

<form asp-action="Edit">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    <input type="hidden" asp-for="SingleItem.Id" name="Id" />
    <div class="form-group col-lg-4" style="padding-left:0px;">
        <input asp-for="SingleItem.Label" name="Label" class="form-control" />
        <span asp-validation-for="SingleItem.Label" class="text-danger"></span>
    </div>
    <div class="form-group col-lg-6" style="padding-left:0px;">
        <input asp-for="SingleItem.Description" name="Description" class="form-control" />
        <span asp-validation-for="SingleItem.Description" class="text-danger"></span>
    </div>
    <div class="form-group col-lg-1" style="padding-left:0px;">
        <input asp-for="SingleItem.SortOrder" name="SortOrder" class="form-control" />
        <span asp-validation-for="SingleItem.SortOrder" class="text-danger"></span>
    </div>
    <div class="form-group col-lg-1" style="padding-left:0px;">
        <button type="submit" value="Save" class="btn btn-xs btn-success">
            <span class="glyphicon glyphicon-floppy-disk"></span>
        </button>
        <a href="/Admin/ProductIdentifiers" class="btn btn-xs btn-warning">
            <span class="glyphicon glyphicon-chevron-left"></span>
        </a>
    </div>
</form>

我不必对控制器中的Edit方法进行任何更改。