MVC 3 несколько DisplayFor-Templates

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

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

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

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

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


person Nischo    schedule 29.04.2011    source источник
comment
Вы должны опубликовать код для вашего шаблона(ов) отображения.   -  person JustinP8    schedule 29.04.2011
comment
также, каков ваш тип b.Items? Множественное число заставляет меня думать, что это коллекция? разве ваш шаблон не должен быть для IEnumerable (Of BasketItem) или что-то в этом роде?   -  person M Thelen    schedule 29.04.2011


Ответы (4)


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

@for (int i = 0; i < Model.Items.Length; i++)
{
    @Html.DisplayFor(x => x.Items[i], "CustomerItemBaseList")
}
person Darin Dimitrov    schedule 29.04.2011
comment
Я надеялся, что это сработает по-другому, но спасибо, теперь я знаю, что могу не пытаться =) - person Nischo; 02.05.2011
comment
Это прекрасно сработало для меня. Статья Фила Хакеда дополнила оставшиеся детали. haacked.com/archive/2008/10/ 23/model-binding-to-a-list.aspx - person Ishmael Smyrnow; 18.08.2011

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

    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")
person Dan Csharpster    schedule 01.11.2013
comment
Я столкнулся с парой незначительных проблем, о которых, возможно, захотят узнать другие: Чтобы использовать DisplayFor в помощнике, ему нужен using System.Web.Mvc.Html; (и Studio не будет предлагать его в качестве опции для привязки). Чтобы увидеть помощника со страницы ASP, вам нужно <%@ Import Namespace="YourNamespace" %> - person Chuck Wilbur; 13.05.2014
comment
А, хорошо, Чак. Я использую Resharper, поэтому, если бы у меня была эта проблема, он бы предложил автоматически исправить ее для меня. Я настоятельно рекомендую его любому разработчику .NET. Я считаю, что есть один или два конкурирующих инструмента. Попробуйте и их, если хотите. - person Dan Csharpster; 13.05.2014
comment
@DanCsharpster Спасибо, только что скорректировано для любого IEnumerable в моем ответе. - person Darren; 10.05.2015

Мне понравился ответ Дэна, но я немного изменил его, так как он может работать для любого 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")
person Darren    schedule 10.05.2015

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

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

таким образом, помощник отлично работает с IEnumerable<T>, вызывая для каждого элемента (подкласса T) относительный DisplayTemplate, передавая ему значения additionalViewData из словаря 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;
    }
}

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

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

person MauriDev    schedule 04.02.2016