为啥将 ViewModel 传递给 View 时会出现此错误?

Posted

技术标签:

【中文标题】为啥将 ViewModel 传递给 View 时会出现此错误?【英文标题】:Why do I get this error when passing ViewModel to View?为什么将 ViewModel 传递给 View 时会出现此错误? 【发布时间】:2021-06-09 09:43:34 【问题描述】:

将 ViewModel 传递给 View 时出现错误

传入 ViewDataDictionary 的模型项是类型 'System.Collections.Generic.List'1[TraficAlert.Models.TaBarHeader]', 但是这个 ViewDataDictionary 实例需要一个类型的模型项 'System.Collections.Generic.IEnumerable'1[TraficAlert.Models.ViewModels.HeaderTelegramaViewModel]'。

我尝试在Index.cshtml 中使用@model IEnumerable<TraficAlert.Models.ViewModels.HeaderTelegramaViewModel>,它可以工作,但我需要从HeaderTelegramaViewModel 访问属性。

Index.cshtml

@model IEnumerable<TraficAlert.Models.ViewModels.HeaderTelegramaViewModel>

<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.TaBarHeader.Id)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.TaBarHeader.ParentId)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.TaBarHeader.TStamp)
            </th>
   (...)
    </thead>
    <tbody>
        @foreach (var item in Model)
        
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.TaBarHeader.Id)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.TaBarHeader.ParentId)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.TaBarHeader.TStamp)
                </td>
   (...)
                <td>
                    <a asp-action="Edit" asp-route-id="@item.TaBarHeader.Id">Edit</a> |
                    <a asp-action="Details" asp-route-id="@item.TaBarHeader.Id">Details</a> |
                    <a asp-action="Delete" asp-route-id="@item.TaBarHeader.Id">Delete</a>
                </td>
            </tr>
        
    </tbody>
</table>

HeaderTelegramaController

(...)
    public IActionResult Index()
    
        var applicationDbContext = _unitofwork.BarHeader.GetAllBarH().ToList();
        return View(applicationDbContext);
    

TaBarHeaderRepository

public IEnumerable<TaBarHeader> GetAllBarH()

    return _db.TaBarHeaders
        .Include(t => t.CategoriaFk)
        .Include(t => t.CauzaFk)
        .Include(t => t.ClasaFk)
        .Include(t => t.LucrareFk)
        .Include(t => t.RegionalaFk)
        .Include(t => t.UserFk);

HeaderTelegramaViewModel

public TaBarHeader TaBarHeader  get; set; 
public IEnumerable<SelectListItem> Categoria  get; set; 
public IEnumerable<ViewOtf> ViewOTFCollection  get; set; 
(...)

为什么会出现上述错误?

谢谢。

【问题讨论】:

正如错误消息所说,它预期 HeaderTelegramaViewModel 的集合,但您已经传递了 TaBarHeader 的集合。您必须将 TaBarHeader 的集合映射到 HeaderTelegramaViewModel 的集合,或者更改视图的 @model 我在HeaderTelegramaViewModel 中创建了public IEnumerable&lt;TaBarHeader&gt; TaBarHeaders get; set; ,并在没有IEnumerable 的情况下更改了@model,但不起作用。 GetAllBarH 返回 TypeA 并且您的视图需要 TypeB。根据提供的代码,两者之间没有隐式转换。因此,问题与ListIEnumerable 无关,而是与它们的参数化类型有关。 现在我明白了。但是,我对如何在方法GetAllBarH() 中使用HeaderTelegramaViewModel 以及这样做的良好做法有点困惑。 您不应该在您的GetAllBarH 中使用HeaderTelegramaViewModel。映射应该在 Controller 的 Action 内完成。您可以手动完成,也可以使用 3rd 方库,例如 AutoMapper 【参考方案1】:

在cshtml中使用下面的模型。

@model TraficAlert.Models.ViewModels.HeaderTelegramaViewModel

并在 Index() 中创建 HeaderTelegramaViewModel 的实例:

var _HeaderTelegramaViewModel = new HeaderTelegramaViewModel();
_HeaderTelegramaViewModel.TaBarHeader = TaBarHeader;

而且 HeaderTelegramaViewModel 类必须有:

public IEnumerable<TaBarHeader> TaBarHeader  get; set;  
public IEnumerable<SelectListItem> Categoria  get; set;  
public IEnumerable<ViewOtf> ViewOTFCollection  get; set; 

【讨论】:

如果我使用 @model TraficAlert.Models.ViewModels.HeaderTelegramaViewModel 我收到此错误 > foreach 语句无法对“HeaderTelegramaViewModel”类型的变量进行操作,因为“HeaderTelegramaViewModel”不包含公共实例或扩展定义'GetEnumerator' 在 cshtml 中使用它来访问元素列表:@foreach(Model.TaBarHeader 中的变量项) 我改了,原来的错误> 模型项传入ViewDataDictionary... 我认为这可能与IEnumerable&lt;TaBarHeader&gt; GetAllBarH()的方法有关。 谢谢!我解决了这个问题,你的答案是最接近的。我在 Index.cshtml 中使用了@model HeaderTelegramaViewModel;在 HeaderTelegramaViewModel 中声明属性 IEnumerable&lt;TaBarHeader&gt; taBarHeader get; set; ;在 HeaderTelegramaController 中更改:HeaderTelegramaViewModel headerTelegramaViewModel = new HeaderTelegramaViewModel(); headerTelegramaViewModel.taBarHeader = _unitofwork.BarHeader.GetAllBarH().ToList();;并更改了 Index.cstml 中的 for:@foreach (var item in Model.taBarHeader).【参考方案2】:

使用 :: @model TraficAlert.Models.ViewModels.HeaderTelegramaViewModel

而不是 ::@model IEnumerable

在 index.cshtml 页面的顶部

【讨论】:

【参考方案3】:

查看模型的类型 IEnumerable 并应用:

   public IActionResult Index()
   
       var applicationDbContext = _unitofwork.BarHeader.GetAllBarH();
       return View(applicationDbContext);
   

【讨论】:

【参考方案4】:

错误消息相当清楚地解释了问题:您传递的类型与视图预期的不同。

具体来说,您调用GetAllBarH() 来获取视图的数据,它会返回IEnumerable&lt;TaBarHeader&gt;。因此页面的model 声明应该是:

@model IEnumerable<TraficAlert.Models.TaBarHeader>

如果你真的想要HeaderTelegramaViewModel,那么你将不得不以某种方式转换IEnumerable&lt;TaBarHeader&gt;。我假设你错过了控制器中的那一步。

【讨论】:

【参考方案5】:

为什么会出现上述错误?

因为您的操作返回的数据类型与视图所需的数据类型不同。

您可以像这样修改您的 HeaderTelegramaController

public IActionResult Index()

   var applicationDbContext = _unitofwork.BarHeader.GetAllBarH().Select(m => new HeaderTelegramaViewModel  TaBarHeader = m ).ToList();
   return View(applicationDbContext);

【讨论】:

【参考方案6】:

我认为可能来自您的表头的错误 考虑到您的模型是IEnumerable,请尝试指定索引。

所以改变

@Html.DisplayFor(modelItem => item.TaBarHeader.Id)

这样的事情

@Html.DisplayFor(modelItem => item[0].TaBarHeader.Id)

【讨论】:

以上是关于为啥将 ViewModel 传递给 View 时会出现此错误?的主要内容,如果未能解决你的问题,请参考以下文章

将事件传递给 ViewModel 的最佳方式是啥?

ViewBagViewData 和 TempData 属性

为啥传递给函数的协议默认值不会改变,即使函数在子类化时会改变?

Vue的生命周期

为啥SqlClient 在传递SqlXml 时会使用不必要的XML 转换?

SwiftUI 将 Int 值传递给 ViewModel