在MVC中使用扩展覆盖默认的html helper

本文关键字:默认 html helper 覆盖 扩展 MVC | 更新日期: 2023-09-27 18:10:06

在这一点上,这更像是一个理论问题,但无论如何都是这样。

简短版本:是否有办法让我自己的html helper取代标准的html helper(如EditBoxFor),而不去替换所有路由(覆盖默认的helper?)或限制替换所有功能在VS视图?

长版:我们构建了一个MVC应用程序,它有很多很多视图,但现在我们的客户希望我们添加功能,让他可以改变应用程序中的各种文本。它与输入的标签、占位符之类的东西有关。我已经为EditBoxFor(在它的心脏,它仍然使用和EditBoxFor)写了我自己的html helper替换,从数据库加载占位符等,把它放在缓存中等等。我将其命名为(哦,如此巧妙)EditBoxFor2,它采用与EditBoxFor相同的输入,因此在视图中,我可以将2添加到助手名称中,它支持这个新的文本功能。EditBoxFor在系统中使用了很多次,它不是我们正在修改的唯一html帮助器。我可能会用EditBoxFor(或更好的Html.EditBoxFor(Html.EditBoxFor2()代替所有EditBoxFor,而不是手工更改几千行代码,但我很可能会以这种方式打破一些视图'控制器'其他助手(我可能忘记在我的Html.EditBoxFor2中实现EditBoxFor的几个变体)。所以我想知道是否有某种方式来覆盖(如在相同的名称和相同的输入参数)与我自己的默认助手?

在MVC中使用扩展覆盖默认的html helper

您可以通过定义显示模板或编辑模板(这些是您可以谷歌的关键字)来实现。

长话短说,你在你的文件夹~/Views/Shared中创建了一个文件夹"DisplayTemplates"和一个文件夹"EditorTemplates"。这是惯例。

然后在这些文件夹中,您可以为每个默认编辑器添加模板。

我用它来为我的电话号码提供模板。

PhoneNumber。cshtml(应该是你的类名)

@model MyProject.Common.Models.PhoneNumber
<div class="editor-field">
    @Html.DisplayFor(model => model.PhoneNumberType)
    @Html.DisplayFor(model => model.Phone)
</div>

我也用它来显示我的枚举

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)
} 

这样,每次我有一个enum类型的字段要显示,它将调用我的帮助器来显示它。帮助器将在resources.resx中搜索合适的字符串。

关于编辑器,它将显示一个下拉列表来选择您想要的enum

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))
}

这是帮助器

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();
    }
}

我认为你可以对你的编辑器使用同样的技术

正如Chris Pratt所写的那样,没有好的方法可以做到这一点,而且从一开始就这样做可能不是一个好主意。这可能最终会让其他在项目上工作的人感到非常困惑(我已经经历过,当其他开发人员修改MVC应用程序的一些基本行为时,然后我不得不花几个小时只是为了找到一些基本的东西不能按预期方式工作的原因)。