This is a migrated thread and some comments may be shown as answers.

KendoUI T4 Template for VS2010

2 Answers 326 Views
Templates
This is a migrated thread and some comments may be shown as answers.
Shane P
Top achievements
Rank 1
Shane P asked on 03 Feb 2012, 02:38 AM
I have spent the last week or so using kendo with a MVC3 project. While learning Kendo I have also been playing around with T4 templating.

I have written a template that uses the default List template but I have modified it to use the KendoUI grid.

I thought I would share it with others as hopefully it will some someone else time. It could do with a few tweaks so I might add it to github soon.

<#@ 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>
    <title><#= mvcHost.ViewName #></title>
</head>
<body>
<#
    PushIndent("    ");
}
#>
<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table id="MYGRID">
<thead>
    <tr>
<#
List<ModelProperty> properties = GetModelProperties(mvcHost.ViewDataType);
foreach (ModelProperty property in properties) {
    if (!property.IsPrimaryKey && property.Scaffold) {
#>
        <th data-field="<#= property.AssociationName #>">
            <#= property.AssociationName #>
        </th>
<#
    }
}
#>
        <th></th>
    </tr>
    </thead>
    <tbody>
@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>
}
</tbody>
</table>
<script>
   $(document).ready(function () {
        setTimeout(function () {
         $("#MYGRID").kendoGrid({
                        dataSource: {
                            type: "json",
                            transport: {
                                read: "/GetJsonData"
                            },
                            schema: {
                                model: {
                                    fields: {
                                    item1:{type:"string"},
                                    item2:{type:"string"},
                                    item3:{type:"string"}
                                    }
                                }
                            },
                            pageSize: 10
                        },
                        columns: [{
                                field:"Id",
                                filterable: false
                            },
                            "Column2",
                            "Column3"
                        ]
                    });
        });
    });
</script>
<#
// 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;
    }
}
#>

2 Answers, 1 is accepted

Sort by
0
Oscar
Top achievements
Rank 1
answered on 03 Sep 2012, 03:16 PM
Thanks Shane for sharing this great resource

Did you continue with this amazing T4 project ?


Regards
0
Sagar
Top achievements
Rank 1
answered on 29 Nov 2012, 11:06 AM
Great..
Tags
Templates
Asked by
Shane P
Top achievements
Rank 1
Answers by
Oscar
Top achievements
Rank 1
Sagar
Top achievements
Rank 1
Share this question
or