Как динамически заполнять HTML с помощью модели в цикле foreach в Aspnet.core Razor?

Я действительно пытаюсь динамически заполнять html-код в Asp.Net Core Razor, и я хочу использовать что-то вроде этого:

@model Aktienverwaltung.Models.ProtokollDividenden

foreach (var item in Model)
{
   <div class="form-group row">
       <label asp-for="@item" class="col-lg-3 control-label text-lg-right pt-2" for="inputRounded"></label>
       <div class="col-lg-6">
           <input asp-for="@item" class="form-control input-rounded" id="inputRounded" />
       </div>
       <span asp-validation-for="@item" class="text-danger"></span>
   </div>
}

это часть моего контроллера:

public async Task<IActionResult> Edit(Guid? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var protokollDividenden = await _context.ProtokollDividenden.FindAsync(id);
    if (protokollDividenden == null)
    {
        return NotFound();
    }
    // return View(await _context.ProtokollDividenden.ToListAsync());
    return View(protokollDividenden);
}

и Модель:

public partial class ProtokollDividenden
    {
        public Guid Id { get; set; }
        public string Aktie { get; set; }
        public string Depotname { get; set; }
        public string Wkn { get; set; }
        public string Kuerzel { get; set; }
        public double Dividende { get; set; }
        public DateTime Datum { get; set; }
        public bool BereitsVerarbeitet { get; set; }
    }

Все, что я пробовал, идет не так, потому что я не могу перечислить Модель или что-то еще. Я тоже пробовал его как список (см. Раскомментированную область в контроллере), но я не могу заставить работать цикл foreach - у кого-нибудь есть идея?


person fahr    schedule 08.03.2019    source источник
comment
Возможный дубликат привязки модели к списку MVC 4   -  person Owen Pauling    schedule 08.03.2019
comment
Только не используйте foreach. Вы не можете перечислить одиночное значение. Вы перечисляете списки, массивы, словари и т. Д. foreach (var item in Model) должен вызывать исключение. Если вы знаете, что у вас есть одно значение, нет причин использовать foreach   -  person Panagiotis Kanavos    schedule 08.03.2019
comment
Кстати, ваш HTML вообще не пытается привязать поля модели. Вы пытались связать все поля в цикл?   -  person Panagiotis Kanavos    schedule 08.03.2019


Ответы (1)


Во-первых, вы можете перечислить только enumerable, то есть IEnumerable<T>, List<T> и т. Д. Прямо сейчас у вас есть только один элемент в качестве модели, поэтому foreach очевидно завершится ошибкой.

Предполагая, что вы действительно возвращаете перечислимую модель, ваша следующая проблема - привязка модели. Чтобы правильно привязать данные, которые вы публикуете, к параметру вашего действия, типы списков должны быть названы в соответствии с форматом CollectionProperty[N].Property, где N - это индекс. Чтобы такие вещи, как помощники тегов, могли генерировать правильные name атрибуты во входных данных формы, им необходимо полное выражение модели. Вы можете думать о выражении модели как о карте определенного свойства, к которому вы пытаетесь привязаться.

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

Здесь концепция аналогична. Использование foreach и создание переменной item в основном удаляет первую часть направлений. Помощники тегов знают, как перейти от item к свойству, к которому вы привязаны, но они не знают, как добраться до item. Таким образом, вы получите такие имена, как item.Foo, которые не смогут быть привязаны к чему-либо значимому. Вместо этого вам нужно использовать цикл for и полное выражение модели, используя индекс в цикле:

@for (var i = 0; i < Model.Count; i++) // assuming `Model` is a list
{
    <input asp-for="@Model[i].Foo" />
}

Стоит отметить, что значение asp-for выше - это специальная конструкция, необходимая, потому что Model сам по себе является списком, который вы повторяете. Если бы вместо этого это было свойство списка в модели, вы бы просто использовали asp-for="ListProperty[i].Foo". Часть @Model существует просто потому, что перед индексирующей нотацией должен использоваться какой-то фактический член. Я видел, как люди запутались в этом и начали пытаться поставить @Model перед всем, то есть @Model.ListProperty[i].Foo.

ИЗМЕНИТЬ

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

Есть Html.EditorFor и Html.EditorForModel (которые, как я думаю, все еще существуют в ASP.NET Core ... Я не использую их лично). Оба являются «шаблонными помощниками», что означает, что они полагаются на шаблоны, чтобы определить, как они обрабатывают то, что им передается. Поскольку вы работаете со своей моделью непосредственно здесь, вам понадобится Html.EditorForModel, который вы использовали бы буквально с помощью следующего кода вместо всего остального кода текущего представления:

@Html.EditorForModel()

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

<label for="Id">Id</label>
<input id="Id" name="Id" value="" />

<label for="Aktie">Aktie</label>
<input id="Aktie" name="Aktie" value="" />

<label for="Depotname">Depotname</label>
<input id="Depotname" name="Depotname" value="" />

...

С этим есть несколько очевидных проблем. В нем нет ваших классов или структуры Bootstrap, поэтому он будет выглядеть ужасно. Это очень просто в интерпретации типа для отображения ввода. Например, Id - это то, чего на самом деле, вероятно, вообще не должно быть, или, если он присутствует, это должен быть скрытый ввод. Aktie может быть длинным текстовым полем, но вы всегда получите ввод, а не что-то вроде textarea. Возможно, Depotname должен быть select со списком возможных вариантов, но, опять же, вы получите только базовый ввод текста. Этот список можно продолжить.

Некоторые из них можно исправить легче, чем другие. Чтобы получить скрытый ввод, примените атрибут [HiddenInput] к свойству в вашем классе. Атрибут DataType может быть применен, чтобы дать больше контекста. Например, если вам нужен textarea, вы можете применить [DataType(DataType.MultilineText)] к свойству в вашем классе. Если вам нужно изменить текст метки, вы можете сделать это с помощью [Display(Name = "My Label Text")].

Для более сложных вещей здесь начинают появляться шаблоны. Например, вы можете создать представление типа Views\Shared\EditorTemplates\String.cshtml и внутри добавить:

@model string

<div class="form-group row">
   <label asp-for="@Model" class="col-lg-3 control-label text-lg-right pt-2" for="inputRounded"></label>
   <div class="col-lg-6">
       <input asp-for="@Model" class="form-control input-rounded" id="inputRounded" />
   </div>
   <span asp-validation-for="@Model" class="text-danger"></span>

Then, this will be used for any string type member. As you might imagine, you can add other such views like DateTime.cshtml, Int32.cshtml, etc., which will each be used for their respective types. You can also add templates for any of the members of that DataType enum, so you can have MultilineText.cshtml, EmailAddress.cshtml, etc. Finally, there is a UIHint attribute that can be applied to specify any template. For example, if you applied [UIHint("Foo")] to a property, then Foo.cshtml would be used.

Вы также можете создавать шаблоны для своих собственных типов. Так, например, у вас может быть ProtokollDividenden.cshtml, и тогда это представление будет фактически использоваться в качестве шаблона для этого класса, а это значит, что оно будет использоваться для вашего вызова @Html.EditorForModel().

Однако при всем этом важно отметить, что после того, как вы добавите настраиваемый шаблон, теперь вы несете за это 100% ответственность. Другими словами, если бы вы добавили представление для всей своей модели, тогда это возьмёт верх, и Html.EditorForModel фактически больше не будет генерировать отдельные поля для вас, в основном вернув вас к той же проблеме, с которой вы начали. Вместо этого он просто сбросит ваш настраиваемый шаблон и прекратит работу.

person Chris Pratt    schedule 08.03.2019
comment
спасибо Крис, но это все еще не работает, Model.Count всегда равен 1 и должно быть 8 элементов - посмотрите на модель, пожалуйста !? Мне нужны поля в модели, а не в модели :-) - person fahr; 08.03.2019
comment
Я не уверен, откуда вы берете 8, хотя предполагаю, потому что ваша модель состоит из 8 членов, это источник. Если это так, то вы действительно ничего не понимаете, что здесь происходит. Члены класса не подлежат перечислению. Вы должны обращаться к ним индивидуально, т.е. <input asp-for="Aktie" />. Это базовый C # 101. На самом деле, это базовое программирование 101, если честно. Вам нужно сделать шаг назад и по-настоящему понять, как работают основные структуры данных в языках программирования. - person Chris Pratt; 08.03.2019
comment
Да, я новичок в C #, но я знаю, что не могу получить доступ к члену, это был мой вопрос - как я могу заполнить HTML членами класса - я думаю, должен быть способ, не так ли? Я не знаю, как это решить ... - person fahr; 08.03.2019