ASP.NET MVC-расширение TextBoxFor без перезаписи метода

есть ли какой-либо возможный способ расширить базовые HTML-помощники (TextBoxFor, TextAreaFor и т. д.), Используя методы расширения на их выходе, а не просто переписывая все методы полностью? Например, добавление ...

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

Я знаю, что могу достичь этого, используя следующее..

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

но это становится неуклюжим и неприятным для управления, когда вам нужно начать добавлять много свойств. Есть ли способ добавить расширения для них по своей сути, не просто проходя в htmlAttributes за каждую мелочь?

2 ответов


как говорит @AaronShockley, потому что TextBoxFor() возвращает MvcHtmlString, ваш единственный вариант для разработки стиля "fluid API" для изменения вывода будет работать на MvcHtmlStrings возвращается вспомогательными методами. Немного другой способ сделать это, который, я думаю, приближается к тому, что вам нужно, - использовать объект "Property builder", например:

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

    public string Class { get; set; }
}

...и чтобы настроить методы расширения, как это:

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

затем вы можете делать такие вещи в своем Вид:

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

это дает вам сильную типизацию и intellisense для входных свойств, которые вы можете настроить для каждого метода расширения, добавив свойства в соответствующий подкласс MvcInputBuilder.


все основные 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;
    }
}

тогда вы можете использовать их в виде:

@Html.TextBoxFor(model => model.Name)
     .If(Model.Name.StartsWith("A"))
     .Else(Html.TextBoxFor(model => model.LastName)

чтобы сделать методы расширения, которые изменяют атрибуты в отображаемом теге 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);
}

на id и name атрибуты всегда добавляются HTML-помощники, но если вы хотите работать с атрибутами, которых может не быть (и вам придется добавлять их вместо того, чтобы просто заменять их), вам нужно будет изменить код.