Visual Studio 编辑 AddView 列表后不运行 T4

Visual studio Not run T4 after edit AddView List

提问人:MGDevTech 提问时间:10/7/2023 更新时间:10/7/2023 访问量:16

问:

我从这条路径编辑了 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 模板的步骤:

  1. 进行编辑:在文本编辑器或集成开发环境(如 Visual Studio)中打开指定路径 (C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\ItemTemplates\CSharp\Web\MVC 4\CodeTemplates\AddView\CSHTML) 中的 List.tt 文件。

  2. 编辑模板:根据需要修改 List.tt 文件的内容,以进行所需的更改。

  3. 保存更改:进行编辑后保存 List.tt 文件。

  4. 打开 Visual Studio:打开或重启 Visual Studio

  5. 创建新视图:在 ASP.NET Core 项目中,创建新视图或重新生成应使用修改后的模板的现有视图。右键单击要创建视图的文件夹(例如,在“视图”文件夹中),选择“添加”,然后选择“查看”。

  6. 配置视图选项:在“添加视图”对话框中,配置视图的选项。请确保选择与您编辑的 List.tt 模板相对应的适当模板。

  7. 重新生成代码:单击“添加视图”对话框中的“添加”按钮以重新生成视图。Visual Studio 会将更改应用于 List.tt 模板并相应地生成代码。

模板 T4

评论


答: 暂无答案