MVC 3 несколько DisplayFor-шаблонов

Я пытаюсь создать собственный шаблон для списка элементов корзины. Мне нужно несколько разных шаблонов, так как у меня разные способы отображения элемента, в зависимости от того, находится ли он на веб-странице или в почте. Теперь моя проблема в том, что когда я использую имя по умолчанию, он работает безупречно.

@Html.DisplayFor(b => b.Items)

Но когда я пытаюсь добавить имя шаблона, я получаю завершение, что мои шаблоны должны быть типа списка IEnumerable, а не BasketItem.

@Html.DisplayFor(i => basket.Items, "CustomerItemBaseList")

Любые идеи, где моя ошибка, или почему это невозможно, оцениваются. Спасибо.

Ответ 1

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

@for (int i = 0; i < Model.Items.Length; i++)
{
    @Html.DisplayFor(x => x.Items[i], "CustomerItemBaseList")
}

Ответ 2

Это хорошая идея, Дарин. Я ленивый, хотя, поэтому я хотел бы сделать это на один шаг дальше и сделать фактическим помощником, который обертывает это. Я также вынул выражение лямбда, чтобы упростить его для моего случая, но вы можете легко добавить эту функциональность обратно.

    public static class DisplayTextListExtension
{
    public static MvcHtmlString DisplayForList<TModel>(this HtmlHelper<TModel> html, IEnumerable<string> model, string templateName)
    {
        var tempResult = new StringBuilder();

        foreach (var item in model)
        {
            tempResult.Append(html.DisplayFor(m => item, templateName));
        }

        return MvcHtmlString.Create(tempResult.ToString());
    }
}

Тогда фактическое использование выглядит следующим образом:

                                @Html.DisplayForList(Model.Organizations, "infoBtn")

Ответ 3

Мне понравился ответ Дэна, но он слегка изменился, поскольку он может работать для любого IEnumerable:

using System.Collections;
using System.Text;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace YourProject.Whatever
{
    public static class DisplayExtensions
    {
        public static MvcHtmlString DisplayForIEnumerable<TModel>(this HtmlHelper<TModel> html, IEnumerable model, string templateName)
        {
            var tempResult = new StringBuilder();

            foreach (var item in model)
            {
                var item1 = item;
                tempResult.Append(html.DisplayFor(m => item1, templateName));
            }

            return MvcHtmlString.Create(tempResult.ToString());
        }
    }
}

И, конечно же:

@Html.DisplayForIEnumerable(Model.Organizations, "NameOfYourDisplayTemplate")

Ответ 4

Я предлагаю другое решение, полезное еще больше со списками гетерогенных объектов (например, подклассы BasketItem), используя параметр дополнительныйViewData​​strong > метода DisplayFor, например:

@DisplayFor(b=>b.Items, new { layout="row" })

таким образом хелпер отлично работает с IEnumerable<T>, вызывая для каждого элемента (подкласс T) относительный DisplayTemplate, передавая ему значения дополнительныеViewData​​strong > в словаре ViewData.

В шаблоне может выводиться другой код для разных значений макета.

В приведенном выше примере шаблон с именем View\Shared\DisplayTemplates\ BasketItem (или имя подкласса) должен выглядеть следующим образом:

@model MyProject.BasketItem // or BasketItem subclass
@{ 
    string layout = ViewData["layout"] as string ?? "default";

    switch(layout)
    {
        case "row":
            <div class="row">
            ...
            </div>
        break;
        // other layouts
        ...
        default: // strongly recommended a default case
            <div class="default-view>
            ...
            </div>
        break;
    }
}

Настоятельно рекомендуется всегда указывать код по умолчанию.

Надеюсь, это предложение может помочь.