我正在尝试创建一个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>
<#
}
或者这不可能吗?
答案 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/