提问人:MGDevTech 提问时间:10/7/2023 更新时间:10/7/2023 访问量:16
Visual Studio 编辑 AddView 列表后不运行 T4
Visual studio Not run T4 after edit AddView List
问:
我从这条路径编辑了 T4 List.tt:C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\ItemTemplates\CSharp\Web\MVC 4\CodeTemplates\AddView\CSHTML
以及尝试从此处添加视图时 从控制器添加视图
这是旧代码:
<#@ template language="C#" HostSpecific="True" #>
<#@ output extension=".cshtml" #>
<#@ assembly name="System.ComponentModel.DataAnnotations" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Data.Entity" #>
<#@ assembly name="System.Data.Linq" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.ComponentModel.DataAnnotations" #>
<#@ import namespace="System.Data.Linq.Mapping" #>
<#@ import namespace="System.Data.Objects.DataClasses" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="Microsoft.VisualStudio.Web.Mvc.Scaffolding.BuiltIn" #>
<#
MvcTextTemplateHost mvcHost = MvcTemplateHost;
#>
@model IEnumerable<#= "<" + mvcHost.ViewDataTypeName + ">" #>
<#
// The following chained if-statement outputs the file header code and markup for a partial view, a content page, or a regular view.
if(mvcHost.IsPartialView) {
#>
<#
} else if(mvcHost.IsContentPage) {
#>
@{
ViewBag.Title = "<#= mvcHost.ViewName#>";
<#
if (!String.IsNullOrEmpty(mvcHost.MasterPageFile)) {
#>
Layout = "<#= mvcHost.MasterPageFile#>";
<#
}
#>
}
<h2><#= mvcHost.ViewName#></h2>
<#
} else {
#>
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title><#= mvcHost.ViewName #></title>
</head>
<body>
<#
PushIndent(" ");
}
#>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<#
List<ModelProperty> properties = GetModelProperties(mvcHost.ViewDataType);
foreach (ModelProperty property in properties) {
if (!property.IsPrimaryKey && property.Scaffold) {
#>
<th>
@Html.DisplayNameFor(model => model.<#= property.ValueExpression #>)
</th>
<#
}
}
#>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<#
foreach (ModelProperty property in properties) {
if (!property.IsPrimaryKey && property.Scaffold) {
#>
<td>
@Html.DisplayFor(modelItem => <#= property.ItemValueExpression #>)
</td>
<#
}
}
string pkName = GetPrimaryKeyName(mvcHost.ViewDataType);
if (pkName != null) {
#>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.<#= pkName #> }) |
@Html.ActionLink("Details", "Details", new { id=item.<#= pkName #> }) |
@Html.ActionLink("Delete", "Delete", new { id=item.<#= pkName #> })
</td>
<#
} else {
#>
<td>
@Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
<#
}
#>
</tr>
}
</table>
<#
// The following code closes the asp:Content tag used in the case of a master page and the body and html tags in the case of a regular view page
#>
<#
if(mvcHost.IsContentPage) {
#>
<#
} else if(!mvcHost.IsPartialView && !mvcHost.IsContentPage) {
ClearIndent();
#>
</body>
</html>
<#
}
#>
<#+
// Describes the information about a property on the model
class ModelProperty {
public string Name { get; set; }
public string AssociationName { get; set; }
public string ValueExpression { get; set; }
public string ModelValueExpression { get; set; }
public string ItemValueExpression { get; set; }
public Type UnderlyingType { get; set; }
public bool IsPrimaryKey { get; set; }
public bool IsForeignKey { get; set; }
public bool IsReadOnly { get; set; }
public bool Scaffold { get; set; }
}
// Change this list to include any non-primitive types you think should be eligible for display/edit
static Type[] bindableNonPrimitiveTypes = new[] {
typeof(string),
typeof(decimal),
typeof(Guid),
typeof(DateTime),
typeof(DateTimeOffset),
typeof(TimeSpan),
};
// Call this to get the list of properties in the model. Change this to modify or add your
// own default formatting for display values.
List<ModelProperty> GetModelProperties(Type type) {
List<ModelProperty> results = GetEligibleProperties(type);
foreach (ModelProperty prop in results) {
if (prop.UnderlyingType == typeof(double) || prop.UnderlyingType == typeof(decimal)) {
prop.ModelValueExpression = "String.Format(\"{0:F}\", " + prop.ModelValueExpression + ")";
}
else if (prop.UnderlyingType == typeof(DateTime)) {
prop.ModelValueExpression = "String.Format(\"{0:g}\", " + prop.ModelValueExpression + ")";
}
}
return results;
}
// Call this to determine if property has scaffolding enabled
bool Scaffold(PropertyInfo property) {
foreach (object attribute in property.GetCustomAttributes(true)) {
var scaffoldColumn = attribute as ScaffoldColumnAttribute;
if (scaffoldColumn != null && !scaffoldColumn.Scaffold) {
return false;
}
}
return true;
}
// Call this to determine if the property represents a primary key. Change the
// code to change the definition of primary key.
bool IsPrimaryKey(PropertyInfo property) {
if (string.Equals(property.Name, "id", StringComparison.OrdinalIgnoreCase)) { // EF Code First convention
return true;
}
if (string.Equals(property.Name, property.DeclaringType.Name + "id", StringComparison.OrdinalIgnoreCase)) { // EF Code First convention
return true;
}
foreach (object attribute in property.GetCustomAttributes(true)) {
if (attribute is KeyAttribute) { // WCF RIA Services and EF Code First explicit
return true;
}
var edmScalar = attribute as EdmScalarPropertyAttribute;
if (edmScalar != null && edmScalar.EntityKeyProperty) { // EF traditional
return true;
}
var column = attribute as ColumnAttribute;
if (column != null && column.IsPrimaryKey) { // LINQ to SQL
return true;
}
}
return false;
}
// This will return the primary key property name, if and only if there is exactly
// one primary key. Returns null if there is no PK, or the PK is composite.
string GetPrimaryKeyName(Type type) {
IEnumerable<string> pkNames = GetPrimaryKeyNames(type);
return pkNames.Count() == 1 ? pkNames.First() : null;
}
// This will return all the primary key names. Will return an empty list if there are none.
IEnumerable<string> GetPrimaryKeyNames(Type type) {
return GetEligibleProperties(type).Where(mp => mp.IsPrimaryKey).Select(mp => mp.Name);
}
// Call this to determine if the property represents a foreign key.
bool IsForeignKey(PropertyInfo property) {
return MvcTemplateHost.RelatedProperties.ContainsKey(property.Name);
}
// A foreign key, e.g. CategoryID, will have a value expression of Category.CategoryID
string GetValueExpressionSuffix(PropertyInfo property) {
RelatedModel propertyModel;
MvcTemplateHost.RelatedProperties.TryGetValue(property.Name, out propertyModel);
return propertyModel != null ? propertyModel.PropertyName + "." + propertyModel.DisplayPropertyName : property.Name;
}
// A foreign key, e.g. CategoryID, will have an association name of Category
string GetAssociationName(PropertyInfo property) {
RelatedModel propertyModel;
MvcTemplateHost.RelatedProperties.TryGetValue(property.Name, out propertyModel);
return propertyModel != null ? propertyModel.PropertyName : property.Name;
}
// Helper
List<ModelProperty> GetEligibleProperties(Type type) {
List<ModelProperty> results = new List<ModelProperty>();
foreach (PropertyInfo prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) {
Type underlyingType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
if (prop.GetGetMethod() != null && prop.GetIndexParameters().Length == 0 && IsBindableType(underlyingType)) {
string valueExpression = GetValueExpressionSuffix(prop);
results.Add(new ModelProperty {
Name = prop.Name,
AssociationName = GetAssociationName(prop),
ValueExpression = valueExpression,
ModelValueExpression = "Model." + valueExpression,
ItemValueExpression = "item." + valueExpression,
UnderlyingType = underlyingType,
IsPrimaryKey = IsPrimaryKey(prop),
IsForeignKey = IsForeignKey(prop),
IsReadOnly = prop.GetSetMethod() == null,
Scaffold = Scaffold(prop)
});
}
}
return results;
}
// Helper
bool IsBindableType(Type type) {
return type.IsPrimitive || bindableNonPrimitiveTypes.Contains(type);
}
MvcTextTemplateHost MvcTemplateHost {
get {
return (MvcTextTemplateHost)Host;
}
}
#>
这是新代码:
<#@ template language="C#" HostSpecific="True" #>
<#@ output extension=".cshtml" #>
<#@ assembly name="System.ComponentModel.DataAnnotations" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Data.Entity" #>
<#@ assembly name="System.Data.Linq" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.ComponentModel.DataAnnotations" #>
<#@ import namespace="System.Data.Linq.Mapping" #>
<#@ import namespace="System.Data.Objects.DataClasses" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="Microsoft.VisualStudio.Web.Mvc.Scaffolding.BuiltIn" #>
<#
MvcTextTemplateHost mvcHost = MvcTemplateHost;
#>
@model IEnumerable<#= "<" + mvcHost.ViewDataTypeName + ">" #>
<#
// The following chained if-statement outputs the file header code and markup for a partial view, a content page, or a regular view.
if(mvcHost.IsPartialView) {
#>
<#
} else if(mvcHost.IsContentPage) {
#>
@{
ViewBag.Title = "<#= mvcHost.ViewName#>";
<#
if (!String.IsNullOrEmpty(mvcHost.MasterPageFile)) {
#>
Layout = "<#= mvcHost.MasterPageFile#>";
<#
}
#>
}
<h2>@ViewDate["Title"]</h2>
<#
} else {
#>
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title><#= mvcHost.ViewName #></title>
</head>
<body>
<#
PushIndent(" ");
}
#>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<a asp-action="Create" class="btn btn-primary me-md-2">Create New</a>
</div>
<table class="table">
<tr>
<#
List<ModelProperty> properties = GetModelProperties(mvcHost.ViewDataType);
foreach (ModelProperty property in properties) {
if (!property.IsPrimaryKey && property.Scaffold) {
#>
<th>
@Html.DisplayNameFor(model => model.<#= property.ValueExpression #>)
</th>
<#
}
}
#>
<th>Actions</th>
</tr>
@foreach (var item in Model) {
<tr>
<#
foreach (ModelProperty property in properties) {
if (!property.IsPrimaryKey && property.Scaffold) {
#>
<td>
@Html.DisplayFor(modelItem => <#= property.ItemValueExpression #>)
</td>
<#
}
}
string pkName = GetPrimaryKeyName(mvcHost.ViewDataType);
if (pkName != null) {
#>
<td>
<a class="btn btn-warning me-2" asp-action="Edit" asp-route-id="@item.<#= pkName #>">Edit</a>
<a class="btn btn-info me-2" asp-action="Details" asp-route-id="@item.<#= pkName #>">Details</a>
<a class="btn btn-danger me-2" asp-action="Delete" asp-route-id="@item.<#= pkName #>">Delete</a>
</td>
<#
} else {
#>
<td>
<a class="btn btn-warning me-2" asp-action="Edit" asp-route-id="">Edit</a>
<a class="btn btn-info me-2" asp-action="Details" asp-route-id="">Details</a>
<a class="btn btn-danger me-2" asp-action="Delete" asp-route-id="">Delete</a>
</td>
<#
}
#>
</tr>
}
</table>
<#
// The following code closes the asp:Content tag used in the case of a master page and the body and html tags in the case of a regular view page
#>
<#
if(mvcHost.IsContentPage) {
#>
<#
} else if(!mvcHost.IsPartialView && !mvcHost.IsContentPage) {
ClearIndent();
#>
</body>
</html>
<#
}
#>
<#+
// Describes the information about a property on the model
class ModelProperty {
public string Name { get; set; }
public string AssociationName { get; set; }
public string ValueExpression { get; set; }
public string ModelValueExpression { get; set; }
public string ItemValueExpression { get; set; }
public Type UnderlyingType { get; set; }
public bool IsPrimaryKey { get; set; }
public bool IsForeignKey { get; set; }
public bool IsReadOnly { get; set; }
public bool Scaffold { get; set; }
}
// Change this list to include any non-primitive types you think should be eligible for display/edit
static Type[] bindableNonPrimitiveTypes = new[] {
typeof(string),
typeof(decimal),
typeof(Guid),
typeof(DateTime),
typeof(DateTimeOffset),
typeof(TimeSpan),
};
// Call this to get the list of properties in the model. Change this to modify or add your
// own default formatting for display values.
List<ModelProperty> GetModelProperties(Type type) {
List<ModelProperty> results = GetEligibleProperties(type);
foreach (ModelProperty prop in results) {
if (prop.UnderlyingType == typeof(double) || prop.UnderlyingType == typeof(decimal)) {
prop.ModelValueExpression = "String.Format(\"{0:F}\", " + prop.ModelValueExpression + ")";
}
else if (prop.UnderlyingType == typeof(DateTime)) {
prop.ModelValueExpression = "String.Format(\"{0:g}\", " + prop.ModelValueExpression + ")";
}
}
return results;
}
// Call this to determine if property has scaffolding enabled
bool Scaffold(PropertyInfo property) {
foreach (object attribute in property.GetCustomAttributes(true)) {
var scaffoldColumn = attribute as ScaffoldColumnAttribute;
if (scaffoldColumn != null && !scaffoldColumn.Scaffold) {
return false;
}
}
return true;
}
// Call this to determine if the property represents a primary key. Change the
// code to change the definition of primary key.
bool IsPrimaryKey(PropertyInfo property) {
if (string.Equals(property.Name, "id", StringComparison.OrdinalIgnoreCase)) { // EF Code First convention
return true;
}
if (string.Equals(property.Name, property.DeclaringType.Name + "id", StringComparison.OrdinalIgnoreCase)) { // EF Code First convention
return true;
}
foreach (object attribute in property.GetCustomAttributes(true)) {
if (attribute is KeyAttribute) { // WCF RIA Services and EF Code First explicit
return true;
}
var edmScalar = attribute as EdmScalarPropertyAttribute;
if (edmScalar != null && edmScalar.EntityKeyProperty) { // EF traditional
return true;
}
var column = attribute as ColumnAttribute;
if (column != null && column.IsPrimaryKey) { // LINQ to SQL
return true;
}
}
return false;
}
// This will return the primary key property name, if and only if there is exactly
// one primary key. Returns null if there is no PK, or the PK is composite.
string GetPrimaryKeyName(Type type) {
IEnumerable<string> pkNames = GetPrimaryKeyNames(type);
return pkNames.Count() == 1 ? pkNames.First() : null;
}
// This will return all the primary key names. Will return an empty list if there are none.
IEnumerable<string> GetPrimaryKeyNames(Type type) {
return GetEligibleProperties(type).Where(mp => mp.IsPrimaryKey).Select(mp => mp.Name);
}
// Call this to determine if the property represents a foreign key.
bool IsForeignKey(PropertyInfo property) {
return MvcTemplateHost.RelatedProperties.ContainsKey(property.Name);
}
// A foreign key, e.g. CategoryID, will have a value expression of Category.CategoryID
string GetValueExpressionSuffix(PropertyInfo property) {
RelatedModel propertyModel;
MvcTemplateHost.RelatedProperties.TryGetValue(property.Name, out propertyModel);
return propertyModel != null ? propertyModel.PropertyName + "." + propertyModel.DisplayPropertyName : property.Name;
}
// A foreign key, e.g. CategoryID, will have an association name of Category
string GetAssociationName(PropertyInfo property) {
RelatedModel propertyModel;
MvcTemplateHost.RelatedProperties.TryGetValue(property.Name, out propertyModel);
return propertyModel != null ? propertyModel.PropertyName : property.Name;
}
// Helper
List<ModelProperty> GetEligibleProperties(Type type) {
List<ModelProperty> results = new List<ModelProperty>();
foreach (PropertyInfo prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) {
Type underlyingType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
if (prop.GetGetMethod() != null && prop.GetIndexParameters().Length == 0 && IsBindableType(underlyingType)) {
string valueExpression = GetValueExpressionSuffix(prop);
results.Add(new ModelProperty {
Name = prop.Name,
AssociationName = GetAssociationName(prop),
ValueExpression = valueExpression,
ModelValueExpression = "Model." + valueExpression,
ItemValueExpression = "item." + valueExpression,
UnderlyingType = underlyingType,
IsPrimaryKey = IsPrimaryKey(prop),
IsForeignKey = IsForeignKey(prop),
IsReadOnly = prop.GetSetMethod() == null,
Scaffold = Scaffold(prop)
});
}
}
return results;
}
// Helper
bool IsBindableType(Type type) {
return type.IsPrimitive || bindableNonPrimitiveTypes.Contains(type);
}
MvcTextTemplateHost MvcTemplateHost {
get {
return (MvcTextTemplateHost)Host;
}
}
#>
完成后并重新启动 Visual Studio 2022 Not 后,添加视图以供操作时,新列表不起作用
搜索任何相关文章以解决此问题。
这些说明如下:
以下是重新生成已编辑的 T4 模板的步骤:
进行编辑:在文本编辑器或集成开发环境(如 Visual Studio)中打开指定路径 (
C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\ItemTemplates\CSharp\Web\MVC 4\CodeTemplates\AddView\CSHTML
) 中的List.tt
文件。编辑模板:根据需要修改
List.tt
文件的内容,以进行所需的更改。保存更改:进行编辑后保存
List.tt
文件。打开 Visual Studio:打开或重启 Visual Studio。
创建新视图:在 ASP.NET Core 项目中,创建新视图或重新生成应使用修改后的模板的现有视图。右键单击要创建视图的文件夹(例如,在“视图”文件夹中),选择“添加”,然后选择“查看”。
配置视图选项:在“添加视图”对话框中,配置视图的选项。请确保选择与您编辑的
List.tt
模板相对应的适当模板。重新生成代码:单击“添加视图”对话框中的“添加”按钮以重新生成视图。Visual Studio 会将更改应用于
List.tt
模板并相应地生成代码。
答: 暂无答案
评论