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

时间:2011-02-24 01:24:47

标签: t4

我正在尝试创建一个t4模板,以帮助加快我的创建表单模板。

是否可以添加额外的html,具体取决于是否需要型号的属性? e.g。

  [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>
<#
}

或者这不可能吗?

4 个答案:

答案 0 :(得分:1)

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 :(得分:0)

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

答案 2 :(得分:0)

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

我正在使用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>
<#
    }
}
#>

答案 3 :(得分:0)

T4模板随MVC5而改变。为了在MVC5中实现这一点,我在这里写了一个教程:https://johniekarr.wordpress.com/2015/05/16/mvc-5-t4-templates-and-view-model-property-attributes/