Skip to content

Instantly share code, notes, and snippets.

@WrackedFella
Last active March 22, 2019 22:29
Show Gist options
  • Save WrackedFella/d088cb037c1ced69636b423c18c644e8 to your computer and use it in GitHub Desktop.
Save WrackedFella/d088cb037c1ced69636b423c18c644e8 to your computer and use it in GitHub Desktop.
@model EntityBase
@using System.ComponentModel
@using System.ComponentModel.DataAnnotations
@using System.Reflection
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.Extensions.Localization
@inject IHtmlLocalizer<DataAnnotationResources> DataAnnotationLocalizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@{
bool IsReadOnly(CustomAttributeData a) => a.AttributeType == typeof(ReadOnlyAttribute) && (bool)a.ConstructorArguments[0].Value;
bool IsHidden(CustomAttributeData a) => a.AttributeType == typeof(KeyAttribute) || a.AttributeType == typeof(HiddenInputAttribute);
// Virtual Properties are relationship proxies.
var nonVirtualProps = Model.GetType().GetProperties().Where(p => !p.GetGetMethod().IsVirtual).ToArray();
// Sort the fields into buckets.
var regularInputProperties = nonVirtualProps.Where(p =>
p.SetMethod != null
&& !p.CustomAttributes.Any(IsHidden)
&& !p.CustomAttributes.Any(IsReadOnly)
).OrderBy(p => p.CustomAttributes.FirstOrDefault(a =>
a.AttributeType == typeof(DisplayAttribute))?.NamedArguments.FirstOrDefault(arg =>
arg.MemberName == "Order").TypedValue.Value).ToArray();
var hiddenInputProperties = nonVirtualProps.Where(p => p.CustomAttributes.Any(IsHidden))
.OrderBy(p =>
p.CustomAttributes.FirstOrDefault(a =>
a.AttributeType == typeof(DisplayAttribute))?.NamedArguments.FirstOrDefault(arg =>
arg.MemberName == "Order").TypedValue.Value).ToArray();
var readOnlyProperties = nonVirtualProps.Where(p => p.CustomAttributes.Any(IsReadOnly))
.OrderBy(p =>
p.CustomAttributes.FirstOrDefault(a =>
a.AttributeType == typeof(DisplayAttribute))?.NamedArguments.FirstOrDefault(arg =>
arg.MemberName == "Order").TypedValue.Value).ToArray();
// Used in row building below.
var rowFlag = false;
const string colCap = @"
</div>
<div class=""col-md-6 col-12"">";
const string rowCap = @"
</div>
</div>
<div class=""form-row"">
<div class=""col-md-6 col-12"">";
}
<form method="post">
<div class="form-row">
<div class="col-12">
<div asp-validation-summary="All" class="text-danger"></div>
@foreach (var prop in hiddenInputProperties)
{
<input type="hidden" id="@prop.Name" name="@prop.Name" value="@prop.GetValue(Model)">
}
@if (Model.GetId() != Guid.Empty)
{
<input type="hidden" id="RecordId" name="RecordId" value="@Model.GetId()">
}
<input type="hidden" id="CreatedBy" name="CreatedBy" value="@Model.CreatedBy">
<input type="hidden" id="CreatedDate" name="CreatedDate" value="@Model.CreatedDate">
<input type="hidden" id="ModifiedBy" name="ModifiedBy" value="@Model.ModifiedBy">
<input type="hidden" id="ModifiedDate" name="ModifiedDate" value="@Model.ModifiedDate">
<input type="hidden" id="IsActive" name="IsActive" value="@(Model.IsActive ? "true" : "false")">
</div>
</div>
<div class="form-row">
<div class="col-md-6 col-12">
@foreach (var prop in regularInputProperties)
{
//AttributeCollection attributes = TypeDescriptor.GetProperties(Model)[prop.Name].Attributes;
//var isReadOnly = attributes[typeof(ReadOnlyAttribute)].Equals(ReadOnlyAttribute.Yes);
var uiHintAttribute = prop.CustomAttributes
.FirstOrDefault(a =>a.AttributeType == typeof(UIHintAttribute));
var displayName = (string)prop.CustomAttributes
.FirstOrDefault(a => a.AttributeType == typeof(DisplayNameAttribute))?.ConstructorArguments[0].Value
?? (string)prop.CustomAttributes
.FirstOrDefault(a => a.AttributeType == typeof(DisplayAttribute))?.NamedArguments
.FirstOrDefault(arg => arg.MemberName == "Name").TypedValue.Value;
if (string.IsNullOrEmpty(displayName))
{
continue;
}
var displayFormatString = (string)prop.CustomAttributes.FirstOrDefault(a =>
a.AttributeType == typeof(DisplayFormatAttribute))?.NamedArguments.FirstOrDefault(arg =>
arg.MemberName == "DataFormatString").TypedValue.Value;
var localizedDisplayName = DataAnnotationLocalizer[displayName];
var propType = prop.PropertyType;
if (propType.IsGenericType && propType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
// Get the real type of this nullable property.
propType = propType.GetGenericArguments().Single();
}
var inputType = "";
if (propType == typeof(Guid))
{
<div class="form-group">
<label for="@prop.Name">
@localizedDisplayName
</label>
<select class="form-control" name="@prop.Name" id="@prop.Name">
<option value="">@SharedLocalizer["SelectDefaultItem"]</option>
@{
var options = (IEnumerable<SelectListItem>)ViewData[$"{prop.Name}Options"];
if (options != null && options.Any())
{
foreach (var option in options)
{
if (prop.GetValue(Model)?.ToString().Equals(option.Value, StringComparison.InvariantCultureIgnoreCase) ?? false)
{
<option value="@option.Value" selected="selected">@option.Text</option>
}
else
{
<option value="@option.Value">@option.Text</option>
}
}
}
}
</select>
</div>
}
else if (uiHintAttribute != null && string.Equals(uiHintAttribute.ConstructorArguments[0].Value.ToString(), "DropDownList", StringComparison.InvariantCultureIgnoreCase))
{
<div class="form-group">
<label for="@prop.Name">
@localizedDisplayName
</label>
<select class="form-control" name="@prop.Name" id="@prop.Name">
<option value="">@SharedLocalizer["SelectDefaultItem"]</option>
@{
var options = (IEnumerable<SelectListItem>)ViewData[$"{prop.Name}Options"];
if (options != null && options.Any())
{
foreach (var option in options)
{
if (prop.GetValue(Model)?.ToString().Equals(option.Value, StringComparison.InvariantCultureIgnoreCase) ?? false)
{
<option value="@option.Value" selected="selected">@option.Text</option>
}
else
{
<option value="@option.Value">@option.Text</option>
}
}
}
}
</select>
</div>
}
else if (propType == typeof(string))
{
inputType = "text";
}
else if (propType == typeof(int) || propType == typeof(decimal))
{
inputType = "number";
}
else if (propType == typeof(DateTimeOffset))
{
inputType = "datetime";
}
else if (propType == typeof(bool))
{
inputType = "checkbox";
}
else
{
throw new NotImplementedException($"The Editor Template lacks a display definition for type {propType}.");
}
if (inputType == "checkbox")
{
<div class="btn-group-toggle" data-toggle="buttons">
<label class="btn btn-secondary">
@Html.CheckBox(prop.Name, (bool)prop.GetValue(Model)) @localizedDisplayName
</label>
</div>
}
else
{
<div class="form-group">
<label for="@prop.Name">
@localizedDisplayName
</label>
<input class="form-control" type="@inputType" id="@prop.Name" name="@prop.Name"
value="@(string.IsNullOrEmpty(displayFormatString)
? prop.GetValue(Model)
: string.Format(displayFormatString, prop.GetValue(Model)))">
</div>
}
if (!rowFlag)
{
@Html.Raw(colCap)
rowFlag = true;
}
else
{
@Html.Raw(rowCap)
rowFlag = false;
}
}
</div>
</div>
<div class="form-row">
<div class="col-12">
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</div>
</div>
</form>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment