在 MvcView 脚手架模板中使用视图模型
Using view models in MvcView scaffolding templates
我有视图模型
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 模板。当我从控制器创建一个新视图并将我的模型 class 添加为 ClientIndexViewModel
时,会生成视图模板 ( index.cshtml ),但没有 IEnumerable<Client>
的属性
模板化Index.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<Client>
属性,作为 PropertyMetaData
上枚举的属性
我想我可以在 ModelMEtadataFunctions.include.t4
文件中创建一个方法。只是不太确定怎么做,或者我是否应该这样做
我找到了使这项工作可行的 hack。这绝不是任何理想的使用方式,但考虑到它只是 visual studio 的脚手架代码而不是项目代码,它似乎还不错
首先。对于视图,模型 Class 是我要枚举的实体类型。所以我从客户端实体而不是我的视图模型获取客户端的所有属性。然而模型是错误的(当然)。所以在模板文件中,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
这基本上满足了我的所有需求。它并不理想,并且严重依赖命名约定,我不确定我是否愿意将其移交给其他开发人员。例如,如果在主项目中创建视图模型,这将无法正确构建脚手架,因为它基于数据 class 的单独项目。实体类型名称和视图模型名称也有非常严格的约定,才能正常工作..
请post如果你有更好的主意,我认为这不是最佳做法
如果您的 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);
}
在我之后更通用
我有视图模型
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 模板。当我从控制器创建一个新视图并将我的模型 class 添加为 ClientIndexViewModel
时,会生成视图模板 ( index.cshtml ),但没有 IEnumerable<Client>
的属性
模板化Index.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<Client>
属性,作为 PropertyMetaData
上枚举的属性
我想我可以在 ModelMEtadataFunctions.include.t4
文件中创建一个方法。只是不太确定怎么做,或者我是否应该这样做
我找到了使这项工作可行的 hack。这绝不是任何理想的使用方式,但考虑到它只是 visual studio 的脚手架代码而不是项目代码,它似乎还不错
首先。对于视图,模型 Class 是我要枚举的实体类型。所以我从客户端实体而不是我的视图模型获取客户端的所有属性。然而模型是错误的(当然)。所以在模板文件中,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
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
这基本上满足了我的所有需求。它并不理想,并且严重依赖命名约定,我不确定我是否愿意将其移交给其他开发人员。例如,如果在主项目中创建视图模型,这将无法正确构建脚手架,因为它基于数据 class 的单独项目。实体类型名称和视图模型名称也有非常严格的约定,才能正常工作..
请post如果你有更好的主意,我认为这不是最佳做法
如果您的 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);
}
在我之后更通用