Last active
March 22, 2019 22:29
-
-
Save WrackedFella/d088cb037c1ced69636b423c18c644e8 to your computer and use it in GitHub Desktop.
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
@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