_Layout.cshtml 上带有 ViewModel 的 PartialView

PartialView with a ViewModel on _Layout.cshtml

我有一个包含部分视图的布局页面。部分视图需要循环遍历视图模型上的 属性 以显示类别列表。显示类别时,我需要显示该类别中的文档列表。 /Home/Index 有效,但是当我尝试查看 /Documents/Category/{id} 时,出现错误:

Additional information: The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[ViewModels.DocumentViewModel]', but this dictionary requires a model item of type 'ViewModels.HomeViewModel'.

_Layout.cshtml

... 
<body>

@Html.Partial("_CategoryViewModel")

<div class="content">
    @RenderBody()
</div>

HomeViewModel.cs

public class HomeViewModel {
    ...
    public ICollection<DocumentCategory> Categories { get; set; }
    public ICollection<Documents> Documents { get; set; }
    ...
}

_CategoryViewModel.cshtml(这应该显示所有类别的列表)

@model ViewModels.HomeViewModel
...
@foreach (DocumentCategory item in Model.Categories)
{
    <li>
        <a href="@Url.Action("Category", "Documents", new { @id = @item.CategoryId })" title="View documents in the @item.Name category">
            <span class="fa fa-files-o"></span>&nbsp;@item.Name
        </a>
    </li>
}

DocumentsController.cs

public ActionResult Category(int id)
{
    var thisCategory = _ctx.Categories.Get(c => c.CategoryId == id).FirstOrDefault();
    IEnumerable<DocumentViewModel> docs = null;
    if(thisCategory == null)
    {
        TempData.Add("errorMessage", "Invalid category");
    } else {
        docs = thisCategory.Documents.ToList();
    }

    return View("Category", docs);
}

发生的事情有点道理 - 布局页面上的 PartialView 需要枚举我正在使用的 ViewModel 中不存在的集合。我不知道如何实现这一点 - 唯一的方法似乎是为我网站中的每个 ViewModel 添加类别 属性。

默认情况下,使用 @Html.Partial() 会将当前模型传递给分部视图,并且由于您的 Category.cshtml 视图使用 @model List<DocumentViewModel>,因此 List<DocumentViewModel> 会传递给一个期望 HomeViewModel.

的部分

如果要在每个页面上呈现 HomeViewModel 的部分视图,请使用 @Html.Action() 调用 returns 部分 [=20] 的 ChildActionOnly 方法=]

[ChildActionOnly]
public ActionResult Categories
{
    var model = new HomeViewModel()
    {
        .... // initialize properties
    }
    return PartialView("_CategoryViewModel", model)
}

并在布局中

@Html.Action("Categories", yourControllerName)
// or
@{ Html.RenderAction("Categories", yourControllerName); }

据我所知,您有几个不同的选择。

1. 使用 Html.Action 并创建一个 returns 您的视图的 Action

@Html.Action("Index", "Category") // Or your controller name.

相信 这种方法存在一些性能缺陷,因为整个 MVC 生命周期将再次 运行 以呈现操作的结果。但是随后您可以在调用它的视图中没有正确模型的情况下呈现操作的结果。

有人可能还会争辩说 breaks the MVC pattern,但这可能是值得的。


2. 在您的 _Layout.cshtml 中使用通用模型(或接口),并让您的视图模型继承该模型。

在你的 _Layout.cshtml:

@model IBaseViewModel

并让您所有的视图模型实现此接口。

public interface IBaseViewModel
{
    ICollection<DocumentCategory> Categories { get; set; }
}

public interface IBaseViewModel<T> : IBaseViewModel
{
    T ViewModel {get; set;}
}

因为你将 @Html.Partial("_CategoryViewModel") 放在 _Layout.cshtml 中,我认为它应该在所有页面中可见,所以我认为所有使用 _Layout.cshtml 的控制器都使确保它获得了所需的信息,从而将 Categories 添加到模型中。

我一直使用这种方法来处理面包屑和菜单信息(在所有页面中使用的内容)。然后我有一个基本控制器,确保 Categories 填充了正确的信息。