修改 TT 模板以添加所需的 html 元素

发布于 2024-10-18 23:19:34 字数 772 浏览 0 评论 0原文

我正在尝试创建 t4 模板来帮助加快我的创建表单模板的速度。

是否可以根据模型的属性是否需要添加额外的 html? 例如,

  [Required]
  [Display(Name = "Contact Email Address:")]
  public string ContactEmailAddress { get; set; }

现在在我的 tt 文件中执行类似的操作

foreach (ModelProperty property in GetModelProperties(mvcHost.ViewDataType)) {
if (!property.IsPrimaryKey && !property.IsReadOnly) {
 #>
    <div>
        @Html.LabelFor(model => model.<#= property.Name #>)
        @Html.EditorFor(model => model.<#= property.Name #>)
        @Html.ValidationMessageFor(model => model.<#= property.Name #>)
        if(this.Required==true){<span class="required-field"></span>}
    </div>
<#
}

或者这不可能吗?

I am trying to create a t4 template to help speed up my Create Form template.

Is it possible to add extra html depending if a model's property is required?
e.g.

  [Required]
  [Display(Name = "Contact Email Address:")]
  public string ContactEmailAddress { get; set; }

Now in my tt file do something like

foreach (ModelProperty property in GetModelProperties(mvcHost.ViewDataType)) {
if (!property.IsPrimaryKey && !property.IsReadOnly) {
 #>
    <div>
        @Html.LabelFor(model => model.<#= property.Name #>)
        @Html.EditorFor(model => model.<#= property.Name #>)
        @Html.ValidationMessageFor(model => model.<#= property.Name #>)
        if(this.Required==true){<span class="required-field"></span>}
    </div>
<#
}

Or is this not possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

如何视而不见 2024-10-25 23:19:34

1、打开此文件:

C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\Web\Mvc\Scaffolding\Templates\MvcViewWithContextScaffolder\ModelPropertyFunctions.include.t4

2、向 ModelProperty 添加一些属性

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 EnvDTE.CodeTypeRef Type { get; set; }
    public bool IsPrimaryKey { get; set; }
    public bool IsForeignKey { get; set; }//
    public bool IsReadOnly { get; set; }//
    public bool IsRequired{ get; set;}//Here is your customer Property
    public bool Scaffold { get; set; }
}

3、在该类下添加一个方法

bool IsRequired(EnvDTE.CodeProperty propertyType)
{
    foreach (EnvDTE.CodeAttribute attribute in propertyType.Attributes) 
    {
        if (String.Equals(attribute.FullName, "System.ComponentModel.DataAnnotations.RequiredAttribute", StringComparison.Ordinal))
        {
            return true;
        }
    }
    return false;
}

4、转到该文件的底部修改方法 GetEligibleProperties:

List<ModelProperty> GetEligibleProperties(EnvDTE.CodeType typeInfo) {
    List<ModelProperty> results = new List<ModelProperty>();
    if (typeInfo != null) {
        foreach (var prop in typeInfo.GetPublicMembers().OfType<EnvDTE.CodeProperty>()) {
            if (prop.HasPublicGetter() && !prop.IsIndexerProperty() && IsBindableType(prop.Type)) {
                string valueExpression = GetValueExpressionSuffix(prop);

                results.Add(new ModelProperty {
                    Name = prop.Name,
                    AssociationName = GetAssociationName(prop),
                    ValueExpression = valueExpression,
                    ModelValueExpression = "Model." + valueExpression,
                    ItemValueExpression = "item." + valueExpression,
                    Type = prop.Type,
                    IsPrimaryKey = IsPrimaryKey(prop),
                    IsForeignKey = IsForeignKey(prop),
                    IsRequired=IsRequired(prop),//Here is your customer property.
                    IsReadOnly = !prop.HasPublicSetter(),
                    Scaffold = Scaffold(prop)
                });
            }
        }
    }

    return results;
}

5、转到该文件

C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\Web\Mvc\Scaffolding\Templates\MvcViewWithContextScaffolder\Edit.cs.t4

在 ValidationMessageFor 之前添加以下检查

@Html.ValidationMessageFor(model => model.<#= property.Name #>):

像这样的代码:

<#
            if (property.IsRequired) {
#>
    *<!--your html code-->
<#
            }
#>

1,Open this file:

C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\Web\Mvc\Scaffolding\Templates\MvcViewWithContextScaffolder\ModelPropertyFunctions.include.t4

2, Add some property to ModelProperty

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 EnvDTE.CodeTypeRef Type { get; set; }
    public bool IsPrimaryKey { get; set; }
    public bool IsForeignKey { get; set; }//
    public bool IsReadOnly { get; set; }//
    public bool IsRequired{ get; set;}//Here is your customer Property
    public bool Scaffold { get; set; }
}

3, Add an method out under this class

bool IsRequired(EnvDTE.CodeProperty propertyType)
{
    foreach (EnvDTE.CodeAttribute attribute in propertyType.Attributes) 
    {
        if (String.Equals(attribute.FullName, "System.ComponentModel.DataAnnotations.RequiredAttribute", StringComparison.Ordinal))
        {
            return true;
        }
    }
    return false;
}

4,Go to the bottom of this file to modify the method GetEligibleProperties:

List<ModelProperty> GetEligibleProperties(EnvDTE.CodeType typeInfo) {
    List<ModelProperty> results = new List<ModelProperty>();
    if (typeInfo != null) {
        foreach (var prop in typeInfo.GetPublicMembers().OfType<EnvDTE.CodeProperty>()) {
            if (prop.HasPublicGetter() && !prop.IsIndexerProperty() && IsBindableType(prop.Type)) {
                string valueExpression = GetValueExpressionSuffix(prop);

                results.Add(new ModelProperty {
                    Name = prop.Name,
                    AssociationName = GetAssociationName(prop),
                    ValueExpression = valueExpression,
                    ModelValueExpression = "Model." + valueExpression,
                    ItemValueExpression = "item." + valueExpression,
                    Type = prop.Type,
                    IsPrimaryKey = IsPrimaryKey(prop),
                    IsForeignKey = IsForeignKey(prop),
                    IsRequired=IsRequired(prop),//Here is your customer property.
                    IsReadOnly = !prop.HasPublicSetter(),
                    Scaffold = Scaffold(prop)
                });
            }
        }
    }

    return results;
}

5, go to the file

C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\Web\Mvc\Scaffolding\Templates\MvcViewWithContextScaffolder\Edit.cs.t4

Add the following check before your ValidationMessageFor

@Html.ValidationMessageFor(model => model.<#= property.Name #>):

Codes like this:

<#
            if (property.IsRequired) {
#>
    *<!--your html code-->
<#
            }
#>
飘落散花 2024-10-25 23:19:34

这是可能的,但需要比您这里所做的更多工作。您可以将必需的属性添加到 ModelProperty,然后通过在获取模型属性时查找属性上的必需属性来设置它。您可以查看 .tt 模板中确定属性是否为主键的代码作为示例。

This would be possible but would take more work than what you have here. You could add a Required property to ModelProperty and then set it by looking for the required attribute on the property when getting the model properties. You can take a look at the code that determines whether or not a property is a primary key in the .tt templates for an example.

蓝咒 2024-10-25 23:19:34

如果有人仍在寻找解决方案...

我正在使用 MetadataType 属性在单独的类中定义属性属性,例如“Required”或“DisplayName”。
示例:

[MetadataType(typeof(personMetaData))]
public partial class Person
{

}

public class personMetaData
{
    [DisplayName("Surname")]
    [Required]
    public object Name { get; set; }
}

如果要访问 t4 模板中的这些属性,则必须扩展模板文件中的 ModelProperty 类和创建者。

将以下代码放在模板的底部(例如List.tt)。您必须替换现有的代码。

<#+
// Describes the information about a property on the model
public class ModelProperty
{
    public string Name { get; set; }
    public string ValueExpression { get; set; }
    public Type UnderlyingType { get; set; }
    public bool IsPrimaryKey { get; set; }
    public bool IsReadOnly { get; set; }
    public string DisplayName { get; set; }
}

// Change this list to include any non-primitive types you think should be eligible for display/edit
private 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.
public  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.ValueExpression = "String.Format(\"{0:F}\", " + prop.ValueExpression + ")";
        }
        else if (prop.UnderlyingType == typeof (DateTime))
        {
            prop.ValueExpression = "String.Format(\"{0:g}\", " + prop.ValueExpression + ")";
        }
    }

    return results;
}

// Call this to determine if the property represents a primary key. Change the
// code to change the definition of primary key.
private 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.
private 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.
private IEnumerable<string> GetPrimaryKeyNames(Type type)
{
    return GetEligibleProperties(type).Where(mp => mp.IsPrimaryKey).Select(mp => mp.Name);
}

// Helper
private 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))
        {
            var displayName = prop.Name;

            // Search in Metadata
            var metadata = type.GetCustomAttributes(typeof(MetadataTypeAttribute), true).OfType<MetadataTypeAttribute>().ToArray().FirstOrDefault();

            if (metadata != null)
            {
                var metaPropery = metadata.MetadataClassType.GetProperty(prop.Name);


                if (metaPropery != null)
                {
                    displayName = ((DisplayNameAttribute)metaPropery.GetCustomAttributes(typeof (DisplayNameAttribute), true).First()).DisplayName;
                }
            }


            results.Add(new ModelProperty
                            {
                                Name = prop.Name,
                                ValueExpression = "Model." + prop.Name,
                                UnderlyingType = underlyingType,
                                IsPrimaryKey = IsPrimaryKey(prop),
                                IsReadOnly = prop.GetSetMethod() == null,
                                DisplayName = displayName
                            });
        }
    }

    return results;
}

// Helper
private bool IsBindableType(Type type)
{
    return type.IsPrimitive || bindableNonPrimitiveTypes.Contains(type);
}
#>

现在您可以像这样访问这些属性:

<#
List<ModelProperty> properties = GetModelProperties(mvcHost.ViewDataType);
foreach (ModelProperty property in properties) {
    if (!property.IsPrimaryKey) {
#>
    <th>
        <#= property.DisplayName #><#= property.AllowEmptyStrings ? "*" : "" #>
    </th>
<#
    }
}
#>

If someone still searching for a solution...

I'm using the MetadataType attibute to define the property attributes like Required or DisplayName in a seperate class.
Sample:

[MetadataType(typeof(personMetaData))]
public partial class Person
{

}

public class personMetaData
{
    [DisplayName("Surname")]
    [Required]
    public object Name { get; set; }
}

If you want to access these attributes in the t4-template you have to extend the ModelProperty class and creator in the template-file.

Put the following code at the bottom of your template (e.g. List.tt). You have to replace the existing code.

<#+
// Describes the information about a property on the model
public class ModelProperty
{
    public string Name { get; set; }
    public string ValueExpression { get; set; }
    public Type UnderlyingType { get; set; }
    public bool IsPrimaryKey { get; set; }
    public bool IsReadOnly { get; set; }
    public string DisplayName { get; set; }
}

// Change this list to include any non-primitive types you think should be eligible for display/edit
private 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.
public  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.ValueExpression = "String.Format(\"{0:F}\", " + prop.ValueExpression + ")";
        }
        else if (prop.UnderlyingType == typeof (DateTime))
        {
            prop.ValueExpression = "String.Format(\"{0:g}\", " + prop.ValueExpression + ")";
        }
    }

    return results;
}

// Call this to determine if the property represents a primary key. Change the
// code to change the definition of primary key.
private 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.
private 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.
private IEnumerable<string> GetPrimaryKeyNames(Type type)
{
    return GetEligibleProperties(type).Where(mp => mp.IsPrimaryKey).Select(mp => mp.Name);
}

// Helper
private 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))
        {
            var displayName = prop.Name;

            // Search in Metadata
            var metadata = type.GetCustomAttributes(typeof(MetadataTypeAttribute), true).OfType<MetadataTypeAttribute>().ToArray().FirstOrDefault();

            if (metadata != null)
            {
                var metaPropery = metadata.MetadataClassType.GetProperty(prop.Name);


                if (metaPropery != null)
                {
                    displayName = ((DisplayNameAttribute)metaPropery.GetCustomAttributes(typeof (DisplayNameAttribute), true).First()).DisplayName;
                }
            }


            results.Add(new ModelProperty
                            {
                                Name = prop.Name,
                                ValueExpression = "Model." + prop.Name,
                                UnderlyingType = underlyingType,
                                IsPrimaryKey = IsPrimaryKey(prop),
                                IsReadOnly = prop.GetSetMethod() == null,
                                DisplayName = displayName
                            });
        }
    }

    return results;
}

// Helper
private bool IsBindableType(Type type)
{
    return type.IsPrimitive || bindableNonPrimitiveTypes.Contains(type);
}
#>

Now you can access these attributes like this:

<#
List<ModelProperty> properties = GetModelProperties(mvcHost.ViewDataType);
foreach (ModelProperty property in properties) {
    if (!property.IsPrimaryKey) {
#>
    <th>
        <#= property.DisplayName #><#= property.AllowEmptyStrings ? "*" : "" #>
    </th>
<#
    }
}
#>
浮华 2024-10-25 23:19:34

T4 模板已随 MVC5 发生变化。为了在 MVC5 中完成此任务,我在这里编写了一个教程: https://johniekarr.wordpress.com/2015/05/16/mvc-5-t4-templates-and-view-model-property-attributes/

T4 templates have changed with MVC5. To accomplish this in MVC5, I've written a tutorial here: https://johniekarr.wordpress.com/2015/05/16/mvc-5-t4-templates-and-view-model-property-attributes/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文