KendoUI T4 Template for VS2010

3 posts, 0 answers
  1. Shane P
    Shane P avatar
    86 posts
    Member since:
    Sep 2012

    Posted 02 Feb 2012 Link to this post

    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. Oscar
    Oscar avatar
    25 posts
    Member since:
    Aug 2012

    Posted 03 Sep 2012 Link to this post

    Thanks Shane for sharing this great resource

    Did you continue with this amazing T4 project ?


    Regards
  3. Kendo UI is VS 2017 Ready
  4. Sagar
    Sagar avatar
    7 posts
    Member since:
    Feb 2012

    Posted 29 Nov 2012 Link to this post

    Great..
Back to Top