Помощники ASP.NET MVC, объединение двух htmlAttributes объекта вместе - PullRequest
30 голосов
/ 18 мая 2011

У меня есть ситуация, когда мне нужно написать помощник HTML, чтобы расширить другой помощник HTML. Обычно помощник будет выглядеть следующим образом.

@Html.TextAreaFor(model => model.Content, new { @class = "some css", @data_bind = "some other stuff..." })

Это прекрасно работает, но его нужно заключить в какой-то другой HTML, который всегда одинаков. Я хотел заключить его в капсулу для удобства, вот так.

public static MvcHtmlString CondensedHelperFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes) {
            var stringBuilder = new System.Text.StringBuilder();
            var tag = new TagBuilder("div"); tag.AddCssClass("some_css");
            stringBuilder.Append(toolbar.ToString(TagRenderMode.SelfClosing));

            stringBuilder.Append(htmlHelper.TextAreaFor(expression, htmlAttributes));
            // more tags and such...

            return new MvcHtmlString(stringBuilder.ToString());
        }

Строка stringBuilder.Append(htmlHelper.TextAreaFor... - это то, что я хочу изменить. Класс CSS, который должен идти туда, будет присутствовать всегда . Поэтому я бы предпочел включить это здесь. Однако я хотел бы иметь возможность указывать дополнительные классы CSS в помощнике верхнего уровня. Итак ...

@Html.CondensedHelperFor(model => model.Content, new { @class = "some_other_css" })

И статический css, который всегда будет там, будет скрыт через Помощника.

Есть идеи?

Ответы [ 4 ]

50 голосов
/ 08 сентября 2012

Вы можете сделать это с помощью стандартного вспомогательного метода MVC.

HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)

htmlAttributes это объект

22 голосов
/ 25 мая 2011

Сначала создайте метод (лучше всего создать метод расширения), который преобразует объект в IDictionary через тип отражения:

public static IDictionary<string, object> ToDictionary(this object data) 
{
        if(data == null) return null; // Or throw an ArgumentNullException if you want

        BindingFlags publicAttributes = BindingFlags.Public | BindingFlags.Instance;
        Dictionary<string, object> dictionary = new Dictionary<string, object>();

        foreach (PropertyInfo property in 
                 data.GetType().GetProperties(publicAttributes)) { 
            if (property.CanRead) {
                dictionary.Add(property.Name, property.GetValue(data, null));
            }
        }
        return dictionary;
}

Теперь воспользуйтесь C # 4.0 ExpandoObject, который позволяет добавлять свойства во время выполнения. В итоге вы получите что-то вроде этого:

public static MvcHtmlString CondensedHelperFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes) {
{
    var dictAttributes = htmlAttributes.ToDictionary();

    var result = new ExpandoObject();
    var d = result as IDictionary<string, object>; //work with the Expando as a Dictionary

    if(dictAttributes != null)
    {
        foreach (var pair in dictAttributes)
        {
            d[pair.Key] = pair.Value;
        }
    }

    // Add other properties to the dictionary d here
    // ...

    var stringBuilder = new System.Text.StringBuilder();
    var tag = new TagBuilder("div"); tag.AddCssClass("some_css");
    stringBuilder.Append(toolbar.ToString(TagRenderMode.SelfClosing));
    stringBuilder.Append(htmlHelper.TextAreaFor(expression, result));

    return new MvcHtmlString(stringBuilder.ToString());
}
2 голосов
/ 27 мая 2011

@ pszmyd: вы можете использовать ViewDataDictionary, который уже принимает объект в конструкторе ex.

//
// Summary:
//     Initializes a new instance of the System.Web.Mvc.ViewDataDictionary class
//     by using the specified model.
//
// Parameters:
//   model:
//     The model.
public ViewDataDictionary(object model);

Также то, что вы пытаетесь сделать, достаточно просто - объединение значений ключей. В случае атрибутов html это не просто. ех. Элемент может содержать несколько классов, напр. 'blue dr ltr', разделенные пробелами, а атрибут style использует точку с запятой в качестве разделителя ex. «Ширина: 200px; размер шрифта: 0.8em;». Вам действительно нужно проанализировать и проверить правильность значений (не объединяя классы CSS, а не разделяя их пробелами, как в стиле).

Я бы посоветовал из вашего параметра: object htmlAttributes вы просто создаете: var htmlAttr = new ViewDataDictionary<TModel>(htmlAttributes);

затем создайте пользовательские методы расширения для объединения атрибутов, например.

public static class ViewDataDictionaryExtensions
{
    public static ViewDataDictionary<TModel> MergeClasses<TModel>(this ViewDataDictionary<TModel> dict, string classes)
    {
        if (dict.ContainsKey("class"))
            dict["class"] += " " + classes;
        else
            dict.Add("class", classes);
        return dict;
    }
    public static ViewDataDictionary<TModel> MergeStyles<TModel>(this ViewDataDictionary<TModel> dict, string styles)
    {
        if (dict.ContainsKey("style"))
            dict["style"] += "; " + styles;
        else
            dict.Add("style", styles);
        return dict;
    }
}

Это только очень простая реализация, не учитывающая повторяющиеся значения атрибутов или несколько разделителей. Но надеюсь, вы поняли идею!

0 голосов
/ 26 мая 2011

Когда я это делаю, я обычно создаю частичное представление Тогда я использую RenderPartial:

@Html.Partial(MVC.Shared.MyPartialView_cshtml, new ViewDataDictionary() {  
       { "Content", model.Content},
       { "Css", "some_other_css"},
});

Обычно я также создаю класс Model, чтобы избежать использования магической строки (и ViewDataDictionary), как в примере выше. По вашему мнению, вы можете

  • использовать содержимое: @ ViewBag.Content
  • проверить и использовать css по умолчанию, если пользовательский не указан (@ ViewBag.Css)

Небольшое примечание: также можно изменить шаблон по умолчанию, используемый при вызове TextAreaFor (или другого аналогичного метода). Для этого взгляните на http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-3-default-templates.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...