Pay attention, class. THIS is how you go full-retard with your code.
I took this:
<div class="form-group">
@Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
</div>
</div>
Down to this:
@Html.EditForEx(model => model.Name)
With this:
public static partial class ExtendHtmlHelper2
{
public static MvcHtmlString EditForEx<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
{
return html.EditForEx(expression, (ValidatorProperties)null, (LabelProperties)null, new EditorProperties());
}
public static MvcHtmlString EditForEx<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, CtrlProperties ctrlProperties)
{
ctrlProperties = (ctrlProperties == null) ? new CtrlProperties() : ctrlProperties
return html.EditForEx(expression, ctrlProperties.Validator, ctrlProperties.Label, ctrlProperties.Editor);
}
private static MvcHtmlString EditForEx<TModel, TValue>(this HtmlHelper<TModel> html,
Expression<Func<TModel, TValue>> expression,
ValidatorProperties validatorProperties,
LabelProperties labelProperties,
EditorProperties editorProperties)
{
MvcHtmlString validator = html.BuildValidator(expression, validatorProperties);
MvcHtmlString label = html.BuildLabel(expression, labelProperties);
MvcHtmlString editor = null;
if (editorProperties == null)
{
editorProperties = new EditorProperties();
}
object attributes = editorProperties.BuildAttributes();
editor = html.EditorFor(expression, attributes);
return WrapOuter(label, WrapInner(editor, validator, ControlType.TextBox));
}
private static MvcHtmlString WrapOuter(MvcHtmlString label, MvcHtmlString innerWrap)
{
StringBuilder html = new StringBuilder();
html.AppendLine("<div class=\"form-group\">").AppendLine(label.ToString()).AppendLine(innerWrap.ToString()).AppendLine("</div>");
return new MvcHtmlString(html.ToString());
}
private static MvcHtmlString WrapInner(MvcHtmlString field, MvcHtmlString validation, ControlType ctrlType)
{
StringBuilder html = new StringBuilder();
string ctrlDiv = "<div class=\"col-md-10\"";
switch (ctrlType)
{
case ControlType.CheckBox : ctrlDiv = WrapInnerCheck(field, validation, "USE WrapInnerCheck").ToString(); break;
case ControlType.DropList :
case ControlType.FileUpload :
case ControlType.TextArea :
case ControlType.TextBox : ctrlDiv = string.Concat(ctrlDiv,">"); break;
case ControlType.TextOnly : ctrlDiv = string.Concat(ctrlDiv," style=\"width:280px;\">"); break;
case ControlType.ActionLink :
case ControlType.ActionButton : ctrlDiv = "<div class=\"col-md-offset-2 col-md-10\">"; break;
case ControlType.Image : ctrlDiv = ""; break;
}
if (!string.IsNullOrEmpty(ctrlDiv))
{
html.AppendLine(ctrlDiv).
AppendLine(field.ToString()).
AppendLine((validation != null)?validation.ToString():"").
AppendLine("</div>");
}
return new MvcHtmlString(html.ToString());
}
}
public class CtrlProperties
{
public LabelProperties Label { get; set; }
public ValidatorProperties Validator { get; set; }
public EditorProperties Editor { get; set; }
public UploaderProperties Uploader { get; set; }
public ActionLinkProperties ActionLink { get; set; }
public ButtonProperties Button { get; set; }
public GlyphProperties Glyph { get; set; }
public DropDownProperties DropDown { get; set; }
public CheckBoxProperties CheckBox { get; set; }
public CtrlProperties()
{
this.Editor = null;
this.Label = null;
this.Validator = null;
this.Uploader = null;
this.ActionLink = null;
this.Button = null;
this.Glyph = null;
this.DropDown = null;
this.CheckBox = null;
}
}
public class PropertiesBase
{
public virtual string DefaultClasses { get { return ""; } }
public virtual string DefaultStyles { get { return ""; } }
public AddOrReplace ClassModifier { get; set; }
public AddOrReplace StyleModifier { get; set; }
public string Classes { get; set; }
public string Style { get; set; }
public bool IsDisabled { get; set; }
public ControlFlags CtrlFlags { get; set; }
public string AdditionalMarkup { get; set; }
public PropertiesBase()
{
this.Classes = string.Empty;
this.Style = string.Empty;
this.IsDisabled = false;
this.CtrlFlags = ControlFlags.IsInForm;
this.ClassModifier = AddOrReplace.AddAfter;
}
protected string ApplyClassModifier(string defaultClasses, string newClasses, AddOrReplace modifier)
{
string classes = defaultClasses;
if (!string.IsNullOrEmpty(newClasses))
{
switch (modifier)
{
case AddOrReplace.AddAfter : classes = string.Format("{0} {1}", classes, newClasses); break;
case AddOrReplace.AddBefore : classes = string.Format("{0} {1}", newClasses, classes); break;
case AddOrReplace.Replace : classes = newClasses; break;
default : classes = string.Empty; break;
}
}
return classes;
}
protected string NormalizeStyles(string styles)
{
styles = styles.TrimEnd(';');
styles = (string.IsNullOrEmpty(styles))? styles : string.Concat(styles, ";");
return styles;
}
public virtual object BuildAttributes()
{
return null;
}
}
public class EditorProperties : PropertiesBase
{
public override string DefaultClasses { get { return "form-control"; } }
public int Width { get; set; }
public bool IsInline { get; set; }
public bool HasActionLink { get; set; }
public string Action { get; set; }
public string Controller { get; set; }
public EditorProperties() : base()
{
this.Width = -1;
this.IsInline = false;
this.HasActionLink = false;
this.Action = string.Empty;
this.Controller = string.Empty;
}
public override object BuildAttributes()
{
object attributes = null;
string classes = this.DefaultClasses;
string styles = this.Style;
classes = ApplyClassModifier(classes, this.Classes, this.ClassModifier);
styles = NormalizeStyles(styles);
if (this.Width > 0)
{
styles = string.Format("{0}width:{1};", styles, this.Width);
}
if (this.IsInline)
{
styles = string.Format("{0}display:inline:block;", styles);
}
bool isDisabled = this.IsDisabled;
bool hasClasses = !string.IsNullOrEmpty(classes);
bool hasStyle = !string.IsNullOrEmpty(styles);
if (hasClasses)
{
if (hasStyle && !isDisabled)
{
attributes = new {@class = classes, @style = styles };
}
else if (!hasStyle && isDisabled)
{
attributes = new { @class = classes, @disabled = "disabled" };
}
else if (hasStyle && isDisabled)
{
attributes = new { @class = classes, @disabled = "disabled", @style = styles };
}
else
{
attributes = new { @class = classes };
}
}
else if (hasStyle)
{
if (isDisabled)
{
attributes = new { @disabled = "disabled", @style = styles };
}
else
{
attributes = new { @style = styles};
}
}
else if (isDisabled)
{
attributes = new { @disabled = "disabled" };
}
attributes = new { htmlAttributes = attributes };
return attributes;
}
}
public class LabelProperties :PropertiesBase
{
public override string DefaultClasses { get { return "col-md-2 control-label"; } }
public string LabelText { get; set; }
public bool IsTransparent { get; set; }
public bool CheckRequired { get; set; }
public string GlyphClass { get; set; }
public LabelProperties():base()
{
this.LabelText = string.Empty;
this.IsTransparent = false;
this.CheckRequired = true;
}
public override object BuildAttributes()
{
object attributes = null;
string classes = this.DefaultClasses;
string styles = this.Style;
classes = ApplyClassModifier(classes, this.Classes, this.ClassModifier);
styles = NormalizeStyles(styles);
bool isDisabled = this.IsDisabled;
bool hasClasses = !string.IsNullOrEmpty(classes);
bool hasStyle = !string.IsNullOrEmpty(styles);
if (hasClasses)
{
if (hasStyle && !isDisabled)
{
attributes = new {@class = classes, @style = styles };
}
else if (!hasStyle && isDisabled)
{
attributes = new { @class = classes, @disabled = "disabled" };
}
else if (hasStyle && isDisabled)
{
attributes = new { @class = classes, @disabled = "disabled", @style = styles };
}
else
{
attributes = new { @class = classes };
}
}
else if (hasStyle)
{
if (isDisabled)
{
attributes = new { @disabled = "disabled", @style = styles };
}
else
{
attributes = new { @style = styles};
}
}
else if (isDisabled)
{
attributes = new { @disabled = "disabled" };
}
return attributes;
}
}
public class ValidatorProperties : PropertiesBase
{
public override string DefaultClasses { get { return "field-validation-valid text-danger"; } }
public string ValidationMessage { get; set; }
public ValidatorProperties() : base()
{
this.ValidationMessage = string.Empty;
}
public override object BuildAttributes()
{
object attributes = null;
string classes = this.DefaultClasses;
string styles = this.Style;
classes = ApplyClassModifier(classes, this.Classes, this.ClassModifier);
styles = NormalizeStyles(styles);
bool hasClasses = !string.IsNullOrEmpty(classes);
bool hasStyle = !string.IsNullOrEmpty(styles);
if (hasClasses)
{
if (hasStyle)
{
attributes = new {@class = classes, @style = styles };
}
}
else if (hasStyle)
{
attributes = new { @style = styles };
}
return attributes;
}
}
I can also do things like this:
// if the field is "required", the same code as above will perform special markup on the label
@Html.EditForEx(model => model.NameRequired)
// if the field is required, but I don't want the markup...
@Html.EditForEx(model => model.NameRequired, new CtrlProperties(){Label=new LabelProperties(){CheckRequired=false}})
//if I want the field disabled...
@Html.EditForEx(model=>model.Name, new CtrlProperties(){ Editor = new EditorProperties(){ IsDisabled = true} })
I can change any related component by instantiating the "properties" object for that component, and changing the properties in that object. If a related properties object is not instantiated in the method call, the default (MVC) version of the component is created and used.
If a different web app requires a different appearance, I simply change the required "properties classes, and the entire site reflects that appearance without any extra work in the middle-tier or outward-facing code.
I'm not saying this is the best approach, but it works really well. I did all this despite the fact that I typically just use the basic method 99.9% of the time. As you might guess, I have similar code for the other control types.
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
modified 14-Dec-17 13:00pm.
|