ASP.net MVC - Показать шаблон для коллекции - PullRequest
41 голосов
/ 04 ноября 2011

У меня есть следующая модель в MVC:

public class ParentModel
{
    public string Property1 { get; set; }
    public string Property2 { get; set; }

    public IEnumerable<ChildModel> Children { get; set; }
}

Когда я хочу отобразить все дочерние элементы для родительской модели, я могу сделать:

@Html.DisplayFor(m => m.Children)

Затем я могу создать шаблон отображения ChildModel.cshtml, и DisplayFor автоматически перебирает список.

Что если я хочу создать собственный шаблон для IEnumerable?

@model IEnumerable<ChildModel>

<table>
    <tr>
        <th>Property 1</th>
        <th>Property 2</th>
    </tr>
    ...
</table>

Как создать шаблон отображения с типом модели IEnumerable<ChildModel>, а затем вызвать @Html.DisplayFor(m => m.Children), не жалуясь на неправильный тип модели?

Ответы [ 4 ]

61 голосов
/ 04 ноября 2011

Примерно так:

@Html.DisplayFor(m => m.Children, "YourTemplateName")

или примерно так:

[UIHint("YourTemplateName")]
public IEnumerable<ChildModel> Children { get; set; }

, где, очевидно, у вас будет ~/Views/Shared/DisplayTemplates/YourTemplateName.cshtml:

@model IEnumerable<ChildModel>

<table>
    <tr>
        <th>Property 1</th>
        <th>Property 2</th>
    </tr>
    ...
</table>
8 голосов
/ 03 августа 2013

Это ответ на комментарий Маслоу.Это мой первый вклад в SO, поэтому у меня недостаточно репутации, чтобы комментировать, поэтому я отвечаю как ответ.

Вы можете установить свойство TemplateHint в ModelMetadataProvider.Это автоматически подключит любой IEnumerable к указанному вами шаблону.Я только что попробовал это в моем проекте.Код ниже -

protected override CachedDataAnnotationsModelMetadata CreateMetadataFromPrototype(CachedDataAnnotationsModelMetadata prototype, Func<object> modelAccessor)
    {
        var metaData = base.CreateMetadataFromPrototype(prototype, modelAccessor);
        var type = metaData.ModelType;

        if (type.IsEnum)
        {
            metaData.TemplateHint = "Enum";
        }
        else if (type.IsAssignableFrom(typeof(IEnumerable<object>)))
        {
            metaData.TemplateHint = "Collection";
        }

        return metaData;
    }

Вы в основном переопределяете метод 'CreateMetadataFromPrototype' 'CachedDataAnnotationsModelMetadataProvider' и регистрируете свой производный тип в качестве предпочтительного ModelMetadataProvider.

В вашем шаблоне вы не можете получить прямой доступ кModelMetadata элементов в вашей коллекции.Я использовал следующий код для доступа к ModelMetadata для элементов в моей коллекции -

@model IEnumerable<object>
@{ 
var modelType = Model.GetType().GenericTypeArguments[0];
var modelMetaData = ModelMetadataProviders.Current.GetMetadataForType(null, modelType.UnderlyingSystemType);

var propertiesToShow = modelMetaData.Properties.Where(p => p.ShowForDisplay);
var propertiesOfModel = modelType.GetProperties();

var tableData = propertiesOfModel.Zip(propertiesToShow, (columnName, columnValue) => new { columnName.Name, columnValue.PropertyName });
}

На мой взгляд, я просто вызываю @ Html.DisplayForModel () и шаблон загружается.Нет необходимости указывать 'UIHint' на моделях.

Надеюсь, это имело какое-то значение.

7 голосов
/ 25 апреля 2014

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

Шаблоны отображения ASP.NET- Нет вывода

По сути, вам нужно создать модель, которая подклассов List<T> или Collection<T> и использовать это:

@model ChildModelCollection 

@foreach (var child in Model)
{
    Html.DisplayFor(m => child);
}

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

Итак, для вопроса ОП:

public class ChildModelCollection : Collection<ChildModel> { }

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

1 голос
/ 14 декабря 2014

Фактический «действительный ответ» - это -НЕГО- неправильный ответ на вопрос. Я думаю, что ОП ищет способ иметь шаблон списка, который срабатывает без указания UIHint.

Волшебный материал почти делает работу

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

Изменить реальное поведение?

Откройте ваш любимый дизассемблер. Магия происходит в System.Web.Mvc.Html.TemplateHelpers.ExecuteTemplate. Как видите, нет точек расширения для изменения поведения. Может быть, пул-запрос в MVC может помочь ...

Идите с настоящей магией

Я придумал что-то, что работает. Создать шаблон отображения ~/Views/Shared/DisplayTemplates/MyModel.cshtml.

Объявите модель как тип object.

Если объект представляет собой коллекцию, выполните итерацию и снова визуализируйте шаблон. Если это не коллекция, то покажите объект.

@model object

@if (Model is IList<MyModel>)
{
    var models = (IList<MyModel>)Model;
<ul>
    @foreach (var item in models)
    {
@Html.Partial("DisplayTemplates/MyModel", item)
    }
</ul>
} else {
    var item = (MyModel)Model;
    <li>@item.Name</li>
    }
}

Теперь DisplayFor работает без UIHint.

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