ASP.NET MVC - 在不重写方法的情况下扩展TextBoxFor

Cie*_*iel 8 asp.net-mvc-3

有没有办法在输出上使用扩展方法扩展基本的html助手(TextBoxFor,TextAreaFor等),而不是仅仅重写整个方法?例如,添加...

@Html.TextBoxFor( model => model.Name ).Identity("idName")

我知道我可以使用以下内容实现这一点,已经......

@Html.TextBoxFor( model => model.Name, new { @id = "idName" })

但是,当您必须开始添加大量属性时,管理变得笨拙和令人沮丧.是否有任何方法可以为这些内容添加扩展而无需传递htmlAttributes每一个细节?

Ste*_*kes 9

正如@AaronShockley所说,因为TextBoxFor()返回一个MvcHtmlString,你开发修改输出的'流体API'风格的唯一选择是操作MvcHtmlString辅助方法返回的s.执行此操作的一种略微不同的方法,我认为接近您所使用的将是使用"属性构建器"对象,如下所示:

public class MvcInputBuilder
{
    public int Id { get; set; }

    public string Class { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

...并设置这样的扩展方法:

public static MvcHtmlString TextBoxFor<TModel, TProp>(
    this HtmlHelper<TModel> htmlHelper,
    Expression<Func<TModel, TProp>> expression,
    params Action<MvcInputBuilder>[] propertySetters)
{
    MvcInputBuilder builder = new MvcInputBuilder();

    foreach (var propertySetter in propertySetters)
    {
        propertySetter.Invoke(builder);
    }

    var properties = new RouteValueDictionary(builder)
        .Select(kvp => kvp)
        .Where(kvp => kvp.Value != null)
        .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

    return htmlHelper.TextBoxFor(expression, properties);
}
Run Code Online (Sandbox Code Playgroud)

然后你可以在你的视图中做这样的事情:

@this.Html.TextBoxFor(
    model => model.Name,
    p => p.Id = 7,
    p => p.Class = "my-class")
Run Code Online (Sandbox Code Playgroud)

这为您提供了输入属性的强类型和智能感知,您可以通过向适当的MvcInputBuilder子类添加属性来为每个扩展方法自定义.


小智 6

所有基本的html助手都返回一个类型的对象System.Web.Mvc.MvcHtmlString.您可以为该类设置扩展方法.这是一个例子:

public static class MvcHtmlStringExtensions
{
    public static MvcHtmlString If(this MvcHtmlString value, bool check)
    {
        if (check)
        {
            return value;
        }

        return null;
    }

    public static MvcHtmlString Else(this MvcHtmlString value, MvcHtmlString alternate)
    {
        if (value == null)
        {
            return alternate;
        }

        return value;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以在以下视图中使用它们:

@Html.TextBoxFor(model => model.Name)
     .If(Model.Name.StartsWith("A"))
     .Else(Html.TextBoxFor(model => model.LastName)
Run Code Online (Sandbox Code Playgroud)

要创建修改呈现的HTML标记上的属性的扩展方法,您必须将结果转换为字符串,然后查找并替换您要查找的值.

using System.Text.RegularExpressions;

public static MvcHtmlString Identity(this MvcHtmlString value, string id)
{
    string input = value.ToString();
    string pattern = @"(?<=\bid=")[^"]*";
    string newValue = Regex.Replace(input, pattern, id);
    return new MvcHtmlString(newValue);
}

public static MvcHtmlString Name(this MvcHtmlString value, string id)
{
    string input = value.ToString();
    string pattern = @"(?<=\bname=")[^"]*";
    string newValue = Regex.Replace(input, pattern, id);
    return new MvcHtmlString(newValue);
}
Run Code Online (Sandbox Code Playgroud)

idname属性总是由HTML辅助添加,但是如果你想与属性可能不会在那里工作(你就必须添加它们,而不是仅仅更换他们的),你需要修改代码.