Как получить индекс последовательности/массива в шаблоне редактора?

Case: У меня есть список элементов класса X, отображаемых с использованием шаблона редактора для класса X.

Проблема: Как я могу получить индекс обрабатываемого элемента внутри шаблона редактора?

Ответ 1

Я использую этот HtmlExtension, который возвращает только нужный идентификатор итерации. Это в основном регулярное выражение на ViewData.TemplateInfo.HtmlFieldPrefix, которое фиксирует последний номер.

public static class HtmlExtensions
    public static MvcHtmlString Index(this HtmlHelper html)
    {
        var prefix = html.ViewData.TemplateInfo.HtmlFieldPrefix;
        var m = Regex.Match(prefix, @".+\[(\d+)\]");
        if (m.Success && m.Groups.Count == 2) 
            return MvcHtmlString.Create(m.Groups[1].Value);
        return null;
    }
}

Может использоваться в редакторе для шаблона:

@Html.Index()

Ответ 2

Используйте цикл for вместо каждого для каждого и передайте индексатор в расширение EditorFor; бритва должна справиться с остальными.

@for(var i = 0; i < Model.count(); i++)
{
    @Html.EditorFor(m => Model.ToArray()[i], new { index = i })
}

Update:

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

В шаблоне редактора обращайтесь к элементу через ViewBag

<span> Item Index: @ViewBag.index </span>

Ответ 3

Использование EditorTemplate - лучшее решение при просмотре моделей, содержащих список.

Чтобы найти индекс для визуализации подмодели, вы можете использовать свойство, которое Razor устанавливает по умолчанию:

ViewData.TemplateInfo.HtmlFieldPrefix

Скажем, например, у вас есть следующие модели представлений:

public class ParagraphVM
{
    public int ParagraphId { get; set; }
    public List<LineVM> Lines { get; set; }
}

и

public class LineVM
{
    public int Id { get; set; }

    public string Text {get; set;}
}

и вы хотите иметь возможность редактировать все "LineVM" в "ParagraphVM". Затем вы должны использовать шаблон редактора, чтобы создать представление в следующей папке (если она не существует) с одним и тем же именем в качестве подмодели Views/Shared/EditorTemplates/LineVM.cshtml:

@model MyProject.Web.MVC.ViewModels.Paragraphs.LineVM
@{
     //this will give you the List element like Lines[index_number]
     var field = ViewData.TemplateInfo.HtmlFieldPrefix;
}
<div id="@field">
    @Html.EditorFor(l => l.Text)
</div>

Предполагая, что у вас есть ActionResult Controller, который возвращает представление и передачу viewmodel ParagrapghVM в представление, например Views/Paragraph/_Paragraph.cshtml:

@model MyProject.Web.MVC.ViewModels.Paragraphs.ParagraphVM

@using (Html.BeginForm("Details", "Paragraphs", FormMethod.Post))
{
    @Html.EditorFor(p => p.Lines)
}

В этом представлении будет отображаться так много редакторов для списка Lines, что и элементы, содержащие этот список. Итак, если, например, список свойств ParagraphVM.Lines содержит 3 элемента, он будет выглядеть примерно так:

<div id="#Lines[0]">
   <input id="Lines_0__Text name="Lines[0].Text"/>
</div>
<div id="#Lines[1]">
   <input id="Lines_1__Text name="Lines[1].Text"/>
</div>
<div id="#Lines[2]">
   <input id="Lines_2__Text name="Lines[2].Text"/>
</div>

С этим вы можете точно знать, в какой позиции находятся все элементы в списке, и, например, использовать некоторый javascript для создания карусели или того, что вы хотите с ней делать. Но помните, что для редактирования этого списка вам действительно не нужно знать позицию, поскольку Razor позаботится об этом для вас. Если вы отправите обратно образец ParagraphVM, строки списка будут иметь привязанные значения (если они есть) без какой-либо дополнительной работы.

Ответ 4

Как насчет:

@using System
@using System.Text.RegularExpressions

var i = Convert.ToInt32(Regex.Matches(
             ViewData.TemplateInfo.HtmlFieldPrefix,
             @"\[([0-9]+)?\]")[0].Groups[1].ToString());

Ответ 5

Вы можете использовать @Html.NameFor(m = > m.AnyField). Это выражение выдаст полное имя, включая индекс. Вы можете извлечь индекс там...

Ответ 6

Я думаю, что самый простой способ:

@Regex.Match(ViewData.TemplateInfo.HtmlFieldPrefix, @"(?!\[)\d+(?=\])")

Или как помощник:

    public static string Index(this HtmlHelper html)
    {
        Match m = Regex.Match(html.ViewData.TemplateInfo.HtmlFieldPrefix, @"(?!\[)\d+(?=\])");
        return m.Success ? m.Value : null;
    }

Вдохновленный @Jona и @Ryan Penfold