Reputation: 5657
At this point it's more of a theoretical question, but here it goes anyway.
The short version:
Is there is some way to make my own html helper replace standard html helper (like EditBoxFor
) without going the replace all route (overriding the default helper?) or limit the replace all function in VS to views only?
Long version:
We built an MVC app that has many many views, but now our client wants us to add functionality that will let him change various text in the application. It's related to things like labels for inputs, placeholders and some such. I already wrote my own html helper replacement for EditBoxFor
(in it's heart it still uses and EditBoxFor
) that loads placeholder etc. from database puts it in cache and so on. I named it (oh so cleverly) EditBoxFor2
and it takes same inputs as EditBoxFor
, so in a view I can just add 2
to the helper name and it supports this new text functionality. EditBoxFor
is used in the system many many times and it's not the only html helper that we're modifying. I could probably do a replace all of EditBoxFor
with EditBoxFor
(or better yet Html.EditBoxFor(
with Html.EditBoxFor2(
) instead of changing a few thousand lines of code by hand, but it's very likely I will break some views\controllers\other helpers this way (I might have forgot to implement a few variants of EditBoxFor
in my Html.EditBoxFor2
). So I was wondering if there is some sort of way to override (as in same name and same input parameters) the default helpers with my own?
Upvotes: 2
Views: 1629
Reputation: 5657
As Chris Pratt wrote, there is no good way to do this and it might not be such a good idea to do this in the first place. This might end up being extremely confusing for other people working on the project (I already experienced that when other developers modified some basic behavior of an MVC application and then I had to spend hours just to find the reason why something basic doesn't work in an expected way).
Upvotes: 1
Reputation: 9521
You can do it by defining a display template or an editor template (these are the keywords you can google).
Long story short, you create a folder "DisplayTemplates" and a folder "EditorTemplates" in your folder ~/Views/Shared. It's a convention.
Then in these folders, you can add a template for each default editor.
I use it to provide a template for my phone numbers for example.
PhoneNumber.cshtml (should be the name of your class)
@model MyProject.Common.Models.PhoneNumber
<div class="editor-field">
@Html.DisplayFor(model => model.PhoneNumberType)
@Html.DisplayFor(model => model.Phone)
</div>
I also use it to have a display for my enums
DisplayTemplates/String.cshtml
@using MyProject.Website.Helpers
@{
var type = Nullable.GetUnderlyingType(ViewData.ModelMetadata.ModelType) ?? ViewData.ModelMetadata.ModelType;
@(typeof(Enum).IsAssignableFrom(type) ? EnumViewsHelpers.GetResourceValueForEnumValue(Model) : Model)
}
This way, each time I have a field of type enum to display, it will call my helper to display it. The helper will search the appropriate string in the resources.resx.
Regarding the editor, it will display a dropdownlist to select the enum you want
EditorTemplates/String.cshtml
@using System.Web.Mvc.Html
@using MyProject.Website.Helpers
@{
var type = Nullable.GetUnderlyingType(ViewData.ModelMetadata.ModelType) ?? ViewData.ModelMetadata.ModelType;
@(typeof(Enum).IsAssignableFrom(type) ? Html.ExtEnumDropDownListFor(x => x) : Html.TextBoxFor(x => x))
}
This is the helper
public static class EnumViewsHelpers
{
public static IHtmlString ExtEnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> html, Expression<Func<TModel, TEnum>> expression)
{
var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
var enumType = Nullable.GetUnderlyingType(metadata.ModelType) ?? metadata.ModelType;
var enumValues = Enum.GetValues(enumType).Cast<object>();
var items = from enumValue in enumValues
select new SelectListItem
{
Text = GetResourceValueForEnumValue(enumValue),
Value = ((int)enumValue).ToString(),
Selected = enumValue.Equals(metadata.Model)
};
return html.DropDownListFor(expression, items, string.Empty, null);
}
public static string GetResourceValueForEnumValue<TEnum>(TEnum enumValue)
{
var key = string.Format("{0}_{1}", enumValue.GetType().Name, enumValue);
return Resource.ResourceManager.GetString(key) ?? enumValue.ToString();
}
}
I think you can use the same technique for your editors
Upvotes: 2