diff --git a/BlankMVCProject/BlankMVCProject.sln b/BlankMVCProject/BlankMVCProject.sln index fb99e40..6db0e8a 100644 --- a/BlankMVCProject/BlankMVCProject.sln +++ b/BlankMVCProject/BlankMVCProject.sln @@ -3,6 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlankMVCProject", "BlankMVCProject\BlankMVCProject.csproj", "{4A957ECA-37F7-4308-A923-195A152EA351}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Twitter.Bootstrap.Utils", "Twitter.Bootstrap.Utils\Twitter.Bootstrap.Utils.csproj", "{C9210E43-2FDC-4154-A3CC-11FC712ABA3F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -13,6 +15,10 @@ Global {4A957ECA-37F7-4308-A923-195A152EA351}.Debug|Any CPU.Build.0 = Debug|Any CPU {4A957ECA-37F7-4308-A923-195A152EA351}.Release|Any CPU.ActiveCfg = Release|Any CPU {4A957ECA-37F7-4308-A923-195A152EA351}.Release|Any CPU.Build.0 = Release|Any CPU + {C9210E43-2FDC-4154-A3CC-11FC712ABA3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C9210E43-2FDC-4154-A3CC-11FC712ABA3F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C9210E43-2FDC-4154-A3CC-11FC712ABA3F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C9210E43-2FDC-4154-A3CC-11FC712ABA3F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/BlankMVCProject/BlankMVCProject/BlankMVCProject.csproj b/BlankMVCProject/BlankMVCProject/BlankMVCProject.csproj index 0cdc37e..0e42c21 100644 --- a/BlankMVCProject/BlankMVCProject/BlankMVCProject.csproj +++ b/BlankMVCProject/BlankMVCProject/BlankMVCProject.csproj @@ -72,10 +72,10 @@ + + - - @@ -136,6 +136,9 @@ + + + @@ -143,7 +146,9 @@ + + @@ -211,7 +216,18 @@ + + + + + + + + + {C9210E43-2FDC-4154-A3CC-11FC712ABA3F} + Twitter.Bootstrap.Utils + diff --git a/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/Create.tt b/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/Create.tt index 3b3840b..a1838e7 100644 --- a/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/Create.tt +++ b/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/Create.tt @@ -4,6 +4,8 @@ <#@ assembly name="System.Core" #> <#@ assembly name="System.Data.Entity" #> <#@ assembly name="System.Data.Linq" #> +<#@ assembly name="System.Web.Mvc" #> +<#@ assembly name="Twitter.Bootstrap.Utils" #> <#@ import namespace="System" #> <#@ import namespace="System.Collections.Generic" #> <#@ import namespace="System.ComponentModel.DataAnnotations" #> @@ -11,9 +13,12 @@ <#@ import namespace="System.Data.Objects.DataClasses" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Reflection" #> +<#@ import namespace="System.Web.Mvc" #> +<#@ import namespace="Twitter.Bootstrap.Utils.Attributes" #> <# MvcTextTemplateHost mvcHost = (MvcTextTemplateHost)(Host); #> +@using Twitter.Bootstrap.Utils.Extensions @model <#= 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. @@ -25,7 +30,7 @@ if(mvcHost.IsPartialView) { #> @{ - ViewBag.Title = "<#= mvcHost.ViewName#>"; + ViewBag.Title = "<#= mvcHost.ViewName + " " + mvcHost.ViewDataType.Name#>"; <# if (!String.IsNullOrEmpty(mvcHost.MasterPageFile)) { #> @@ -34,10 +39,6 @@ if (!String.IsNullOrEmpty(mvcHost.MasterPageFile)) { } #> } - - <# } else { #> @@ -50,11 +51,9 @@ if (!String.IsNullOrEmpty(mvcHost.MasterPageFile)) { - <#= mvcHost.ViewName #> + <#= mvcHost.ViewName + " " + mvcHost.ViewDataType.Name#> - <# PushIndent(" "); } @@ -71,23 +70,33 @@ if (mvcHost.ReferenceScriptLibraries) { #> - + <# } #> -@using (Html.BeginForm()) { + + + +@using (Html.BootstrapBeginForm("form-horizontal")) { @Html.ValidationSummary(true)
- <#= mvcHost.ViewDataType.Name #> + <#= mvcHost.ViewName + " " + mvcHost.ViewDataType.Name #> <# foreach (ModelProperty property in GetModelProperties(mvcHost.ViewDataType)) { if (!property.IsPrimaryKey && !property.IsReadOnly) { #>
- @Html.LabelFor(model => model.<#= property.Name #>) + @Html.BootstrapLabelFor(model => model.<#= property.Name #>)
@Html.EditorFor(model => model.<#= property.Name #>) - @Html.ValidationMessageFor(model => model.<#= property.Name #>) + @Html.BootstrapValidationMessageFor(model => model.<#= property.Name #>) +<# +if (!string.IsNullOrEmpty(property.HelperText)) { +#> + @Html.BootstrapFormHelpTextBlockFor(model => model.<#= property.Name #>) +<# +} +#>
@@ -97,15 +106,13 @@ foreach (ModelProperty property in GetModelProperties(mvcHost.ViewDataType)) { #>
+ @Html.ActionLink("Cancel", "Index", null, new {@class = "btn"})
} -
- @Html.ActionLink("Back to List", "Index") -
<# // 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 #> @@ -127,6 +134,7 @@ class ModelProperty { public Type UnderlyingType { get; set; } public bool IsPrimaryKey { get; set; } public bool IsReadOnly { get; set; } + public string HelperText { get; set; } } // Change this list to include any non-primitive types you think should be eligible for display/edit @@ -137,6 +145,7 @@ static Type[] bindableNonPrimitiveTypes = new[] { typeof(DateTime), typeof(DateTimeOffset), typeof(TimeSpan), + typeof(bool) }; // Call this to get the list of properties in the model. Change this to modify or add your @@ -151,6 +160,9 @@ List GetModelProperties(Type type) { else if (prop.UnderlyingType == typeof(DateTime)) { prop.ValueExpression = "String.Format(\"{0:g}\", " + prop.ValueExpression + ")"; } + else if (prop.UnderlyingType == typeof(bool)) { + prop.HelperText = String.Empty; // Checkboxes are handled differently - see EditorTemplates\Boolean.cshtml + } } return results; @@ -210,7 +222,8 @@ List GetEligibleProperties(Type type) { ValueExpression = "Model." + prop.Name, UnderlyingType = underlyingType, IsPrimaryKey = IsPrimaryKey(prop), - IsReadOnly = prop.GetSetMethod() == null + IsReadOnly = prop.GetSetMethod() == null, + HelperText = GetHelperText(prop) }); } } @@ -222,4 +235,21 @@ List GetEligibleProperties(Type type) { bool IsBindableType(Type type) { return type.IsPrimitive || bindableNonPrimitiveTypes.Contains(type); } + +// Helper +string GetHelperText(PropertyInfo property) { + string helperText = String.Empty; + + foreach (object attribute in property.GetCustomAttributes(true)) { + if (attribute is HelperTextAttribute) { // Bootstrap helper text + HelperTextAttribute helper = attribute as HelperTextAttribute; + if (helper != null) { + helperText = helper.HelperText; + } + } + + } + + return helperText; +} #> \ No newline at end of file diff --git a/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/Delete.tt b/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/Delete.tt index d02f9a8..8c0440b 100644 --- a/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/Delete.tt +++ b/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/Delete.tt @@ -25,7 +25,7 @@ if(mvcHost.IsPartialView) { #> @{ - ViewBag.Title = "<#= mvcHost.ViewName#>"; + ViewBag.Title = "<#= mvcHost.ViewName + " " + mvcHost.ViewDataType.Name#>"; <# if (!String.IsNullOrEmpty(mvcHost.MasterPageFile)) { #> @@ -34,10 +34,6 @@ if (!String.IsNullOrEmpty(mvcHost.MasterPageFile)) { } #> } - - <# } else { #> @@ -50,44 +46,42 @@ if (!String.IsNullOrEmpty(mvcHost.MasterPageFile)) { - <#= mvcHost.ViewName #> + <#= mvcHost.ViewName + " " + mvcHost.ViewDataType.Name#> - <# PushIndent(" "); } -#> -

Are you sure you want to delete this?

- @using (Html.BeginForm()) { -
-
- <#= mvcHost.ViewDataType.Name #> -
+#> + + +@using (Html.BeginForm()) { +
+ <#= mvcHost.ViewName + " " + mvcHost.ViewDataType.Name#> +
+ × +

Warning!

+ Are you sure you want to delete this? +
<# foreach (ModelProperty property in GetModelProperties(mvcHost.ViewDataType)) { if (!property.IsPrimaryKey) { #> -
-
@Html.LabelFor(model => model.<#= property.Name #>)
-
@Html.DisplayFor(model => model.<#= property.Name #>)
-
+
+
@Html.LabelFor(model => model.<#= property.Name #>)
+
@Html.DisplayFor(model => model.<#= property.Name #>)
+
<# } } #> -
- -
-
-
-
- } -
- @Html.ActionLink("Back to List", "Index") -
+
+ + @Html.ActionLink("Cancel", "Index", null, new {@class = "btn"}) +
+ +} <# // 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 #> diff --git a/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/Details.tt b/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/Details.tt index 3a83a7a..ec05c39 100644 --- a/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/Details.tt +++ b/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/Details.tt @@ -25,7 +25,7 @@ if(mvcHost.IsPartialView) { #> @{ - ViewBag.Title = "<#= mvcHost.ViewName#>"; + ViewBag.Title = "<#= mvcHost.ViewDataType.Name + " " + mvcHost.ViewName#>"; <# if (!String.IsNullOrEmpty(mvcHost.MasterPageFile)) { #> @@ -34,11 +34,6 @@ if (!String.IsNullOrEmpty(mvcHost.MasterPageFile)) { } #> } - - - <# } else { #> @@ -51,18 +46,15 @@ if (!String.IsNullOrEmpty(mvcHost.MasterPageFile)) { - <#= mvcHost.ViewName #> + <#= mvcHost.ViewDataType.Name + " " + mvcHost.ViewName#> - <# PushIndent(" "); } #>
- <#= mvcHost.ViewDataType.Name #> -
+ <#= mvcHost.ViewDataType.Name + " " + mvcHost.ViewName#> <# foreach (ModelProperty property in GetModelProperties(mvcHost.ViewDataType)) { if (!property.IsPrimaryKey) { @@ -83,18 +75,21 @@ foreach (ModelProperty property in GetModelProperties(mvcHost.ViewDataType)) { string pkName = GetPrimaryKeyName(mvcHost.ViewDataType); if (pkName != null) { #> - @Html.ActionLink("Edit", "Edit", new { id=Model.<#= pkName #> }) | - @Html.ActionLink("Back to List", "Index") +
+ @Html.ActionLink("Edit", "Edit", new { id=Model.<#= pkName #> }, new { @class = "btn btn-primary" }) + @Html.ActionLink("Cancel", "Index", null, new {@class = "btn"}) +
<# } else { #> - @Html.ActionLink("Edit", "Edit", new { /* id=Model.PrimaryKey */ }) | - @Html.ActionLink("Back to List", "Index") +
+ @Html.ActionLink("Edit", "Edit", new { /* id=Model.PrimaryKey */ }, new {@class = "btn btn-primary"} ) + @Html.ActionLink("Cancel", "Index", null, new {@class = "btn"}) +
<# } #>

- <# if(!mvcHost.IsPartialView && !mvcHost.IsContentPage) { ClearIndent(); diff --git a/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/Edit.tt b/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/Edit.tt index e68bb72..678fcfb 100644 --- a/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/Edit.tt +++ b/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/Edit.tt @@ -4,6 +4,8 @@ <#@ assembly name="System.Core" #> <#@ assembly name="System.Data.Entity" #> <#@ assembly name="System.Data.Linq" #> +<#@ assembly name="System.Web.Mvc" #> +<#@ assembly name="Twitter.Bootstrap.Utils" #> <#@ import namespace="System" #> <#@ import namespace="System.Collections.Generic" #> <#@ import namespace="System.ComponentModel.DataAnnotations" #> @@ -11,9 +13,12 @@ <#@ import namespace="System.Data.Objects.DataClasses" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Reflection" #> +<#@ import namespace="System.Web.Mvc" #> +<#@ import namespace="Twitter.Bootstrap.Utils.Attributes" #> <# MvcTextTemplateHost mvcHost = (MvcTextTemplateHost)(Host); #> +@using Twitter.Bootstrap.Utils.Extensions @model <#= 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. @@ -25,7 +30,7 @@ if(mvcHost.IsPartialView) { #> @{ - ViewBag.Title = "<#= mvcHost.ViewName#>"; + ViewBag.Title = "<#= mvcHost.ViewName + " " + mvcHost.ViewDataType.Name#>"; <# if (!String.IsNullOrEmpty(mvcHost.MasterPageFile)) { #> @@ -34,10 +39,6 @@ if (!String.IsNullOrEmpty(mvcHost.MasterPageFile)) { } #> } - - <# } else { #> @@ -50,11 +51,9 @@ if (!String.IsNullOrEmpty(mvcHost.MasterPageFile)) { - <#= mvcHost.ViewName #> + <#= mvcHost.ViewName + " " + mvcHost.ViewDataType.Name#> - <# PushIndent(" "); } @@ -71,14 +70,17 @@ if (mvcHost.ReferenceScriptLibraries) { #> - + <# } #> - @using (Html.BeginForm()) { + + + + @using (Html.BootstrapBeginForm("form-horizontal")) { @Html.ValidationSummary(true)
- <#= mvcHost.ViewDataType.Name #> + <#= mvcHost.ViewName + " " + mvcHost.ViewDataType.Name#> <# foreach (ModelProperty property in GetModelProperties(mvcHost.ViewDataType)) { if (property.IsPrimaryKey) { @@ -92,10 +94,17 @@ foreach (ModelProperty property in GetModelProperties(mvcHost.ViewDataType)) { } else if (!property.IsReadOnly) { #>
- @Html.LabelFor(model => model.<#= property.Name #>) + @Html.BootstrapLabelFor(model => model.<#= property.Name #>)
@Html.EditorFor(model => model.<#= property.Name #>) - @Html.ValidationMessageFor(model => model.<#= property.Name #>) + @Html.BootstrapValidationMessageFor(model => model.<#= property.Name #>) +<# +if (!string.IsNullOrEmpty(property.HelperText)) { +#> + @Html.BootstrapFormHelpTextBlockFor(model => model.<#= property.Name #>) +<# +} +#>
@@ -104,15 +113,12 @@ foreach (ModelProperty property in GetModelProperties(mvcHost.ViewDataType)) { } #>
- + + @Html.ActionLink("Cancel", "Index", null, new {@class = "btn"})
} - -
- @Html.ActionLink("Back to List", "Index") -
<# // 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 #> @@ -134,6 +140,7 @@ class ModelProperty { public Type UnderlyingType { get; set; } public bool IsPrimaryKey { get; set; } public bool IsReadOnly { get; set; } + public string HelperText { get; set; } } // Change this list to include any non-primitive types you think should be eligible for display/edit @@ -144,6 +151,7 @@ static Type[] bindableNonPrimitiveTypes = new[] { typeof(DateTime), typeof(DateTimeOffset), typeof(TimeSpan), + typeof(bool) }; // Call this to get the list of properties in the model. Change this to modify or add your @@ -158,6 +166,9 @@ List GetModelProperties(Type type) { else if (prop.UnderlyingType == typeof(DateTime)) { prop.ValueExpression = "String.Format(\"{0:g}\", " + prop.ValueExpression + ")"; } + else if (prop.UnderlyingType == typeof(bool)) { + prop.HelperText = String.Empty; // Checkboxes are handled differently - see EditorTemplates\Boolean.cshtml + } } return results; @@ -217,7 +228,8 @@ List GetEligibleProperties(Type type) { ValueExpression = "Model." + prop.Name, UnderlyingType = underlyingType, IsPrimaryKey = IsPrimaryKey(prop), - IsReadOnly = prop.GetSetMethod() == null + IsReadOnly = prop.GetSetMethod() == null, + HelperText = GetHelperText(prop) }); } } @@ -229,4 +241,21 @@ List GetEligibleProperties(Type type) { bool IsBindableType(Type type) { return type.IsPrimitive || bindableNonPrimitiveTypes.Contains(type); } + +// Helper +string GetHelperText(PropertyInfo property) { + string helperText = String.Empty; + + foreach (object attribute in property.GetCustomAttributes(true)) { + if (attribute is HelperTextAttribute) { // Bootstrap helper text + HelperTextAttribute helper = attribute as HelperTextAttribute; + if (helper != null) { + helperText = helper.HelperText; + } + } + + } + + return helperText; +} #> \ No newline at end of file diff --git a/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/List-DataTables.tt b/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/List-DataTables.tt new file mode 100644 index 0000000..d3a70a0 --- /dev/null +++ b/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/List-DataTables.tt @@ -0,0 +1,317 @@ +<#@ 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" #> +<# +MvcTextTemplateHost mvcHost = (MvcTextTemplateHost)(Host); +#> +@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.ViewDataType.Name + " List"#>"; +<# +if (!String.IsNullOrEmpty(mvcHost.MasterPageFile)) { +#> + Layout = "<#= mvcHost.MasterPageFile#>"; +<# +} +#> +} + + +<# +} else { +#> + +@{ + Layout = null; +} + + + + + + <#= mvcHost.ViewDataType.Name + " List"#> + + + +<# + PushIndent(" "); +} +#> + + + + + + + + + +<# +List properties = GetModelProperties(mvcHost.ViewDataType); +foreach (ModelProperty property in properties) { + if (!property.IsPrimaryKey) { +#> + +<# + } +} +#> + + + + +@foreach (var item in Model) { + +<# +string pkName = GetPrimaryKeyName(mvcHost.ViewDataType); +if (pkName != null) { +#> + +<# +} else { +#> + +<# +} + +foreach (ModelProperty property in properties) { + if (!property.IsPrimaryKey) { +#> + +<# + } +} +#> + +} + +
+ <#= property.DisplayName ?? property.Name#> +
+ @item.<#= pkName #> + + /* id=item.PrimaryKey */ + + @<#= property.ValueExpression.Replace("Model.", "item.") #> +
+ + + +<# +// 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(); +#> + + +<# +} +#> + +<#+ +// Describes the information about a property on the model +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 +static Type[] bindableNonPrimitiveTypes = new[] { + typeof(string), + typeof(decimal), + typeof(Guid), + typeof(DateTime), + typeof(DateTimeOffset), + typeof(TimeSpan), + typeof(bool) +}; + +// 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 GetModelProperties(Type type) { + List 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. +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 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 GetPrimaryKeyNames(Type type) { + return GetEligibleProperties(type).Where(mp => mp.IsPrimaryKey).Select(mp => mp.Name); +} + +// Helper +List GetEligibleProperties(Type type) { + List results = new List(); + + 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)) { + results.Add(new ModelProperty { + Name = prop.Name, + ValueExpression = "Model." + prop.Name, + UnderlyingType = underlyingType, + IsPrimaryKey = IsPrimaryKey(prop), + IsReadOnly = prop.GetSetMethod() == null, + DisplayName = GetDisplayName(prop) + }); + } + } + + return results; +} + +// Helper +bool IsBindableType(Type type) { + return type.IsPrimitive || bindableNonPrimitiveTypes.Contains(type); +} + +// Helper +string GetDisplayName(PropertyInfo property) { + string displayName = null; + + foreach (object attribute in property.GetCustomAttributes(true)) { + if (attribute is DisplayAttribute) { + DisplayAttribute display = attribute as DisplayAttribute; + if (display != null) { + displayName = display.Name; + } + } + + } + + return displayName; +} +#> \ No newline at end of file diff --git a/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/List.tt b/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/List.tt index cba69e0..d466f76 100644 --- a/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/List.tt +++ b/BlankMVCProject/BlankMVCProject/CodeTemplates/AddView/CSHTML/List.tt @@ -25,7 +25,7 @@ if(mvcHost.IsPartialView) { #> @{ - ViewBag.Title = "<#= mvcHost.ViewName#>"; + ViewBag.Title = "<#= mvcHost.ViewDataType.Name + " List"#>"; <# if (!String.IsNullOrEmpty(mvcHost.MasterPageFile)) { #> @@ -36,7 +36,7 @@ if (!String.IsNullOrEmpty(mvcHost.MasterPageFile)) { } <# } else { @@ -50,7 +50,7 @@ if (!String.IsNullOrEmpty(mvcHost.MasterPageFile)) { - <#= mvcHost.ViewName #> + <#= mvcHost.ViewDataType.Name + " List"#>