在_Layout.cshtml上使用ViewModel的PartialView

时间:2016-08-10 08:08:19

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

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

  

附加信息:传入字典的模型项的类型为'System.Collections.Generic.List`1 [ViewModels.DocumentViewModel]',但此字典需要“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添加一个Categories属性。

2 个答案:

答案 0 :(得分:1)

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

如果您想在每个页面上呈现HomeViewModel的部分视图,请使用@Html.Action()调用返回部分

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 :(得分:0)

我认为你有几种不同的选择。

1。使用Html.Action并创建一个返回视图的$scope.myNameValidate = function(name) { $scope.getAllFriends(name); } $scope.getAllFriends = function(name) { friendService.getAllfriends(name) .then(function(data) { $scope.friendsList = data; console.log("data", $scope.friendsList); }, function(err){ //error }) }

Action

相信这种方法存在一些性能缺点,因为整个MVC生命周期将再次运行以呈现操作的结果。但是,您可以在调用它的视图中呈现操作的结果,而无需使用正确的模型。

有人可能会认为这是breaks the MVC pattern,但它可能是值得的。

2。@Html.Action("Index", "Category") // Or your controller name. 中使用通用模型(或界面),让您的视图模型继承该模型。

_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")中,我认为它应该在所有页面中都可见,因此我认为所有使用{{1}的控制器都是合乎逻辑的{{}} 1}}确保它获取所需的信息,从而将_Layout.cshtml添加到模型中。

我一直使用这种方法来处理面包屑和菜单信息(所有页面中都使用的东西)。然后我有一个basecontroller,确保_Layout.cshtml填充正确的信息。