C# 在MVC中用扩展覆盖默认html帮助程序?

C# 在MVC中用扩展覆盖默认html帮助程序?,c#,asp.net-mvc,visual-studio,C#,Asp.net Mvc,Visual Studio,在这一点上,这更多的是一个理论问题,但无论如何,这就是问题所在 简短版本: 是否有某种方法可以让我自己的html帮助程序替换标准html帮助程序(如EditBoxFor),而无需执行全部替换路由(覆盖默认帮助程序?)或将VS中的全部替换函数仅限于视图 长版本: 我们构建了一个MVC应用程序,它有很多视图,但现在我们的客户希望我们添加一些功能,让他可以更改应用程序中的各种文本。它与输入标签、占位符等相关。我已经为EditBoxFor(在它的核心部分仍然使用和EditBoxFor)编写了自己的htm

在这一点上,这更多的是一个理论问题,但无论如何,这就是问题所在

简短版本: 是否有某种方法可以让我自己的html帮助程序替换标准html帮助程序(如
EditBoxFor
),而无需执行全部替换路由(覆盖默认帮助程序?)或将VS中的全部替换函数仅限于视图

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

您可以通过定义显示模板或编辑器模板来实现(这些是你可以在谷歌上搜索的关键词)

长话短说,在~/Views/Shared文件夹中创建一个文件夹“DisplayTemplates”和一个文件夹“EditorTemplates”。这是一种惯例

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

例如,我使用它为我的电话号码提供一个模板

PhoneNumber.cshtml(应该是您的类名)

这样,每当我有一个enum类型的字段要显示时,它都会调用我的助手来显示它。助手会在resources.resx中搜索适当的字符串

关于编辑器,它将显示一个下拉列表来选择所需的枚举

EditorTemplates/String.cshtml

@using MyProject.Website.Helpers

@{
    var type = Nullable.GetUnderlyingType(ViewData.ModelMetadata.ModelType) ?? ViewData.ModelMetadata.ModelType;

    @(typeof(Enum).IsAssignableFrom(type) ? EnumViewsHelpers.GetResourceValueForEnumValue(Model) : Model)
} 
@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();
    }
}
公共静态类EnumViewsHelpers
{
公共静态IHtmlString ExtEnumDropDownListFor(此HtmlHelper html,表达式)
{
var metadata=modelmetada.FromLambdaExpression(表达式,html.ViewData);
var enumType=Nullable.GetUnderlinegType(metadata.ModelType)??metadata.ModelType;
var enumValues=Enum.GetValues(enumType.Cast();
var items=从enumValues中的enumValue开始
选择新的SelectListItem
{
Text=GetResourceValueForEnumValue(枚举值),
Value=((int)enumValue).ToString(),
所选=enumValue.Equals(metadata.Model)
};
返回html.DropDownListFor(表达式、项、字符串.Empty、null);
}
公共静态字符串GetResourceValueForEnumValue(TEnum enumValue)
{
var key=string.Format(“{0}{1}”,enumValue.GetType().Name,enumValue);
返回Resource.ResourceManager.GetString(键)??enumValue.ToString();
}
}

我认为你可以像克里斯·普拉特(Chris Pratt)所写的那样,对你的编辑使用同样的技巧,没有好的方法可以做到这一点,而且一开始这样做可能不是一个好主意。这可能会让从事该项目的其他人非常困惑(我已经经历过,当其他开发人员修改MVC应用程序的一些基本行为时,我不得不花上几个小时来找出基本功能不能以预期方式工作的原因).

谢谢你的回答,我听说了编辑器模板,但我想我只能将它们与EditorFor helper一起使用,我想我还需要进一步研究。p.S.你的第二个代码示例泄漏了一个“}”在代码块之外。你只能将它们与
EditorFor
DisplayFor
一起使用。我想@MarcinHabuszewski没有仔细阅读,并将
editbox误认为
EditorFor
。我最初是以同样的方式阅读的。没有好的方法来完成这一点,这是有原因的。即使您是目前唯一从事某项工作的开发人员,情况可能并不总是如此。您可能会选择更环保的环境,或者您的组织可能会雇佣其他人。覆盖这样的内容只会在您的代码库中造成混乱。通过使用不同名称的帮助者,您可以清楚地表明这是不同的。当然,这个决定应该是正确的由开发团队决定?这与覆盖任何其他类型的默认行为(例如
modelmataproviders
甚至全局操作过滤器)有何区别?
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();
    }
}