【问题标题】:Using view models in MvcView scaffolding templates在 MvcView 脚手架模板中使用视图模型
【发布时间】:2015-03-31 19:08:50
【问题描述】:

我有视图模型

public class ClientIndexViewModel
{
    [Key]
    public int SurrogateId { get; set; } // not primary key just used in templating
    public IEnumerable<Client> Clients { get; set; }
}

我创建了一个名为Index.cs.t4 的新MvcView t4 模板。当我从控制器创建一个新视图并将我的模型类添加为 ClientIndexViewModel 时,会生成视图模板 ( index.cshtml ),但没有来自 IEnumerable&lt;Client&gt; 的属性

模板化索引.cshtml

<table class="table">
<!-- Client properties should be here .. i think -->
<tr>
    <th></th> <!-- This is all empty because i dont really know what i am doing -->
</tr>

@foreach (var item in Model) {
<tr>
    <td>
        @Html.ActionLink("Edit", "Edit", new { id=item.SurrogateId }) |
        @Html.ActionLink("Details", "Details", new { id=item.SurrogateId }) |
        @Html.ActionLink("Delete", "Delete", new { id=item.SurrogateId })
    </td>
</tr>
}

当我查看模板文件时,这是有道理的。

Index.cs.t4

<#
IEnumerable<PropertyMetadata> properties = ModelMetadata.Properties;
foreach (PropertyMetadata property in properties) {
if (property.Scaffold && !property.IsPrimaryKey && !property.IsAssociation)     {
#>
<#
    if (property.IsAssociation && GetRelatedModelMetadata(property) == null)     {
        continue;
    }
#>
    <th>
        @Html.DisplayNameFor(model => model.<#= GetValueExpression(property)     #>)
    </th>
<#
    }
}
#>

我希望能够专门针对properties 变量的视图模型上的IEnumerable&lt;Client&gt; 属性,作为PropertyMetaData 上的枚举属性

我想我可以在ModelMEtadataFunctions.include.t4 文件中创建一个方法。只是不太确定如何,或者我什至应该这样做

【问题讨论】:

  • 您确定将 ClientIndexViewModel 作为模型添加到 Templated Index.cshtml 中吗?
  • @MuratYıldız 作为对话框中的类模型?是的。

标签: asp.net-mvc t4 scaffolding asp.net-mvc-scaffolding


【解决方案1】:

我发现了一个使这项工作有效的 hack。这绝不是任何理想的使用方式,但考虑到它只是 Visual Studio 的脚手架代码而不是项目代码,它似乎并不算太​​糟糕

首先。对于视图,模型类是我要枚举的实体类型。所以我从客户端实体而不是我的视图模型中获取客户端的所有属性。然而模型是错误的(当然)。所以在模板文件中,Index.cs.t4 我根据ViewDataTypeShortName 参数(在Imports.include.t4 中找到)更改了控制块。这给了我 Client ,因为我正在选择客户端实体。

例如在foreach 中,它通常会显示

 @foreach (var item in Model){
 <tr>
    <td>
        @Html.DisplayFor(modelItem => <#= "item." + GetValueExpression(property) #>) 
    </td>
 </tr>
 }

现在我通过添加来控制它

@foreach (var item in Model.<#= NewViewDataTypeShortName #>)
// NewViewDataTypeShortName is created with 
// <# string NewViewDataTypeShortName = ViewDataTypeShortName + 's'; #> 
// Based on my naming convention.

Index.cshtml 中产生这个

@foreach (var item in Model.Clients) {

然后我通过在ModelMetaDataFunctions.cs.include.t4 中创建一个方法来添加我的@model

string GetViewModelName(string ViewDataTypeName,string   
                       ViewDataTypeShortName,string ViewName){

       string[] names = ViewDataTypeName.Split(new string[]{"."},StringSplitOptions.None);
       return names[0] + ".Domain.ViewModels." + 
       ViewDataTypeShortName + ViewName +"ViewModel";
}

Index.cs.t4中这样调用

@model <#= GetViewModelName(ViewDataTypeName,ViewDataTypeShortName,ViewName) #>

然后在Index.cshtml中显示为

@model TaskR.Domain.ViewModels.ClientIndexViewModel

这基本上给了我我需要的一切。它并不理想,并且严重依赖于命名约定,我不确定我是否愿意移交给另一个开发人员。例如,如果视图模型是在主项目中创建的,这将无法正确搭建,因为它基于数据类的单独项目。实体类型名称和视图模型名称也有一个非常严格的约定才能工作..

如果您有更好的想法,请发布,我认为这不是最佳做法

【讨论】:

    【解决方案2】:

    如果您的 Models 文件夹与 ViewModels 文件夹位于您可以使用的同一文件夹根目录中

    string GetViewModelName(string ViewDataTypeName,string   
                       ViewDataTypeShortName,string ViewName){
    
       string[] names = ViewDataTypeName.Split('.');
       names[names.Length-2] = "ViewModels";
       names[names.Length-1] = names[names.Length-1]+"ViewModel";
       return string.Join(".",names);
    }
    

    在我之后更通用

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-31
      • 1970-01-01
      • 2015-03-16
      • 2020-05-16
      • 2013-11-15
      • 2012-03-27
      • 2011-02-13
      相关资源
      最近更新 更多