-
Notifications
You must be signed in to change notification settings - Fork 134
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #24 from dglaser/master
Code Templates for Issue #17
- Loading branch information
Showing
7 changed files
with
1,504 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,313 @@ | ||
<#@ 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 <#= 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> | ||
<meta name="viewport" content="width=device-width" /> | ||
<title><#= mvcHost.ViewName #></title> | ||
</head> | ||
<body> | ||
<# | ||
PushIndent(" "); | ||
} | ||
#> | ||
<# | ||
if (mvcHost.ReferenceScriptLibraries) { | ||
#> | ||
<# | ||
if (!mvcHost.IsContentPage) { | ||
#> | ||
<script src="~/Scripts/jquery-1.7.1.min.js"></script> | ||
<script src="~/Scripts/jquery.validate.min.js"></script> | ||
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script> | ||
|
||
<# | ||
} | ||
} | ||
#> | ||
@using (Html.BeginForm()) { | ||
@Html.ValidationSummary(true) | ||
|
||
<fieldset> | ||
<legend><#= mvcHost.ViewDataType.Name #></legend> | ||
|
||
<# | ||
foreach (ModelProperty property in GetModelProperties(mvcHost.ViewDataType)) { | ||
if (!property.IsPrimaryKey && !property.IsReadOnly && property.Scaffold) { | ||
#> | ||
<div class="control-group"> | ||
<# | ||
if (property.IsForeignKey) { | ||
#> | ||
@Html.LabelFor(model => model.<#= property.Name #>, "<#= property.AssociationName #>") | ||
<# | ||
} else { | ||
#> | ||
@Html.LabelFor(model => model.<#= property.Name #>) | ||
<# | ||
} | ||
#> | ||
|
||
<div class="controls"> | ||
<# | ||
if (property.IsForeignKey) { | ||
#> | ||
@Html.DropDownList("<#= property.Name #>", String.Empty) | ||
<# | ||
} else { | ||
#> | ||
@Html.EditorFor(model => model.<#= property.Name #>) | ||
<# | ||
} | ||
#> | ||
@Html.ValidationMessageFor(model => model.<#= property.Name #>, string.Empty, new { @class="help-inline" }) | ||
</div> | ||
</div> | ||
|
||
<# | ||
} | ||
} | ||
#> | ||
<div class="control-group"> | ||
<div class="controls"> | ||
<input type="submit" value="Create" class="btn" /> @Html.ActionLink("Cancel", "Index") | ||
</div> | ||
</div> | ||
</fieldset> | ||
} | ||
|
||
<# | ||
if(mvcHost.IsContentPage && mvcHost.ReferenceScriptLibraries) { | ||
#> | ||
|
||
@section Scripts { | ||
@Scripts.Render("~/bundles/jqueryval") | ||
|
||
<script> | ||
|
||
$.validator.setDefaults({ | ||
highlight: function (element) { | ||
$(element).closest(".control-group").addClass("error"); | ||
}, | ||
unhighlight: function (element) { | ||
$(element).closest(".control-group").removeClass("error"); | ||
} | ||
}); | ||
</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.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; | ||
} | ||
} | ||
#> |
Oops, something went wrong.