ак создать индексы индексов префиксов без шаблонов MVC HTML Editor?

—ледующий код был исчерпан, но в основном ¤ хочу добитьс¤ следующего:

я хотел бы иметь возможность редактировать вопросы и их ответы на ответы, име¤ возможность динамически добавл¤ть / удал¤ть вопросы / варианты ответов со страницы. ¬ идеале, HtmlFieldPrefix дл¤ моих элементов будет непоследовательным, но public class QuestionViewModel {public int QuestionId {get; задавать; } public IEnumerable <AnswerChoiceViewModel> AnswerChoices {get; задавать; }} () использует последовательный индекс.

” мен¤ есть QuestionModel Question, который содержит IEnumerable of Answer Choices:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Models.QuestionViewModel>" %>

<%=Html.HiddenFor(m => m.QuestionId)%>
<%=Html.EditorFor(m => m.AnswerChoices) %>

¬ частичном представлении вопроса (Question.ascx) у мен¤ есть следующее:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Models.AnswerChoiceViewModel>" %>

<%=Html.HiddenFor(m => m.AnswerChoiceId)%>
<%=Html.TextBoxFor(m => m.Name)%>

» шаблон редактора выбора ответа (AnswerChoiceViewModel.ascx):

<input type="hidden" id="QuestionId" value="1" />
<input type="hidden" id="Question.AnswerChoices[0].AnswerChoiceId" value="1" />
<input type="hidden" id="Question.AnswerChoices[0].Name" value="Answer Choice 1" />

<input type="hidden" id="QuestionId" value="2" />
<input type="hidden" id="Question.AnswerChoices[1].AnswerChoiceId" value="2" />
<input type="hidden" id="Question.AnswerChoices[1].Name" value="Answer Choice 2" />

 огда ¤ выдаю Question.ascx, вывод будет выгл¤деть следующим образом:

<input type="hidden" id="QuestionId" value="1" />
<input type="hidden" id="Question.AnswerChoices[e1424d5e-5585-413c-a1b0-595f39747876].AnswerChoiceId" value="1" />
<input type="hidden" id="Question.AnswerChoices[e1424d5e-5585-413c-a1b0-595f39747876].Name" value="Answer Choice 1" />

<input type="hidden" id="QuestionId" value="2" />
<input type="hidden" id="Question.AnswerChoices[633db1c3-f1e6-470b-9c7f-c138f2d9fa71].AnswerChoiceId" value="2" />
<input type="hidden" id="Question.AnswerChoices[633db1c3-f1e6-470b-9c7f-c138f2d9fa71].Name" value="Answer Choice 2" />

я хочу знать, как ¤ могу предоставить EditorFor пользовательский индекс GUID, чтобы страница отображалась следующим образом:

    #region CollectionItem helper
    private const string idsToReuseKey = "__htmlPrefixScopeExtensions_IdsToReuse_";

    public static IDisposable BeginCollectionItem(this HtmlHelper html, string collectionName)
    {
        var idsToReuse = GetIdsToReuse(html.ViewContext.HttpContext, collectionName);
        string itemIndex = idsToReuse.Count > 0 ? idsToReuse.Dequeue() : Guid.NewGuid().ToString();

        // autocomplete="off" is needed to work around a very annoying Chrome behaviour whereby it reuses old values after the user clicks "Back", which causes the xyz.index and xyz[...] values to get out of sync.
        html.ViewContext.Writer.WriteLine(string.Format("<input type="hidden" name="{0}.index" autocomplete="off" value="{1}" />", collectionName, itemIndex));

        return BeginHtmlFieldPrefixScope(html, string.Format("{0}[{1}]", collectionName, itemIndex));
    }

    public static IDisposable BeginHtmlFieldPrefixScope(this HtmlHelper html, string htmlFieldPrefix)
    {
        return new HtmlFieldPrefixScope(html.ViewData.TemplateInfo, htmlFieldPrefix);
    }

    private static Queue<string> GetIdsToReuse(HttpContextBase httpContext, string collectionName)
    {
        // We need to use the same sequence of IDs following a server-side validation failure,  
        // otherwise the framework won't render the validation error messages next to each item.
        string key = idsToReuseKey + collectionName;
        var queue = (Queue<string>)httpContext.Items[key];
        if (queue == null)
        {
            httpContext.Items[key] = queue = new Queue<string>();
            var previouslyUsedIds = httpContext.Request[collectionName + ".index"];
            if (!string.IsNullOrEmpty(previouslyUsedIds))
                foreach (string previouslyUsedId in previouslyUsedIds.Split(','))
                    queue.Enqueue(previouslyUsedId);
        }
        return queue;
    }

    private class HtmlFieldPrefixScope : IDisposable
    {
        private readonly TemplateInfo templateInfo;
        private readonly string previousHtmlFieldPrefix;

        public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix)
        {
            this.templateInfo = templateInfo;

            previousHtmlFieldPrefix = templateInfo.HtmlFieldPrefix;
            templateInfo.HtmlFieldPrefix = htmlFieldPrefix;
        }

        public void Dispose()
        {
            templateInfo.HtmlFieldPrefix = previousHtmlFieldPrefix;
        }
    }

    #endregion

я уже написал вспомогательный метод, который получит индекс префикса текущего контекста и сохранит его в скрытом поле Ђ.Indexї, чтобы некорректные индексы могли быть св¤заны правильно. ѕросто хочу знать, как EditorFor назначает индексы, чтобы ¤ мог переопределить его (или любое другое рабочее решение).

c#,asp.net-mvc,editorfor,asp.net-mvc-templates,

2

Ответов: 5


<@using (Html.BeginCollectionItem ("AnswerChoices")) {@ Html.HiddenFor (m => m.AnswerChoiceId) @ Html.TextBoxFor (m => m.Name)} type = "hidden" name = "_ id_" значение = "11267659"> голосуйте 2

¬ то врем¤ как ¤ занималс¤ этой проблемой и столкнулс¤ с записью —. —андерсона (создател¤ Knockoutjs), где он описал и решил аналогичную проблему. я использовал часть своего кода и пыталс¤ изменить его в соответствии с моими потребност¤ми. я помещаю код ниже в некоторый класс (exapmle: Helpers.cs), добавл¤ем пространство имен в web.config.

        @{
            var index = Guid.NewGuid();
            var prefix = Regex.Match(ViewData.TemplateInfo.HtmlFieldPrefix, @"^(.+)[d+]$").Groups[1].Captures[0].Value;
            //TODO add a ton of error checking and pull this out into a reusable class!!!!
            ViewData.TemplateInfo.HtmlFieldPrefix = prefix + "[" + index + "]";
        }
        <input type="hidden" name="@(prefix).Index" value="@index"/>

ѕосле того, как вы можете сделать EditTemplate или частичным, как это

@using TestMVC.Models
@using System.Text.RegularExpressions
@model Phone
    <div class="form-horizontal">
        <hr />
        @{
            var index = Guid.NewGuid();
            var prefix = Regex.Match(ViewData.TemplateInfo.HtmlFieldPrefix, @"^(.+)[d+]$").Groups[1].Captures[0].Value;
            //TODO add a ton of error checking and pull this out into a reusable class!!!!
            ViewData.TemplateInfo.HtmlFieldPrefix = prefix + "[" + index + "]";
        }
        <input type="hidden" name="@(prefix).Index" value="@index"/>
        <div class="form-group">
            @Html.LabelFor(model => model.Number, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Number, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Number, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.IsEnabled, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                <div class="checkbox">
                    @Html.EditorFor(model => model.IsEnabled)
                    @Html.ValidationMessageFor(model => model.IsEnabled, "", new { @class = "text-danger" })
                </div>
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Details, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.TextAreaFor(model => model.Details, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Details, "", new { @class = "text-danger" })
            </div>
        </div>
    </div>

» перечислите свой шаблон рендеринга списка (частичный).


1

ћне потребовалось больше времени, чем нужно было пон¤ть. ” всех слишком много работы, чтобы сделать это. —екретный соус - это четыре строки кода:

<div class="form-group">
@Html.LabelFor(model => model.Phones, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
    @Html.EditorFor(model => model.Phones, new { htmlAttributes = new { @class = "form-control" } })
</div>
</div>

“еперь, что это такое? ћы получаем новый guid, это наш новый индекс дл¤ замены целочисленного, который автоматически назначаетс¤. «атем мы получим префикс пол¤ по умолчанию, и мы отменим этот индекс int, который нам не нужен. ѕосле подтверждени¤ того, что мы создали некоторый технический долг, мы затем обновл¤ем viewdata, чтобы все вызовы editorfor теперь использовали это как новый префикс. Ќаконец, мы добавим ввод, который будет отправлен обратно в прив¤зку модели, указав индекс, который он должен использовать, чтобы св¤зать эти пол¤ вместе.

√де эта маги¤ должна произойти? ¬нутри шаблона редактора: /Views/Shared/EditorTemplates/Phone.cshtml

        [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "ContactId,FirstName,LastName,Phones")] Contact contact)
    {
        if (ModelState.IsValid)
        {

            db.Contacts.Add(contact);
            db.SaveChanges();
            //TODO need to update this to save phone numbers
            return RedirectToAction("Index");
        }

        return View(contact);
    }

EditorTemplate?  акие?!  ак?! ѕросто поместите его в указанную выше директорию, использу¤ им¤ объекта дл¤ имени файла. ѕусть конвенци¤ MVC работает своей магией. — вашего основного вида просто добавьте редактор дл¤ этого свойства IEnumerable:

Html.EditorFor

“еперь, вернитесь в свой контроллер, убедитесь, что вы обновили свою подпись метода, чтобы прин¤ть, что ienumerable (Bind include Phones):

input

 ак добавить и удалить их на странице? ƒобавьте несколько кнопок, прив¤жите некоторый JavaScript, добавьте метод к контроллеру, который вернет представление дл¤ этой модели. Ajax, чтобы схватить его и вставить в страницу. я позволю вам разобратьс¤ с этими детал¤ми, поскольку на данный момент это просто зан¤та¤ работа.


0

Html.EditorForэто не что иное, как так называемый метод помощника Html, который отображает inputвсе атрибуты.

≈динственное решение, которое приходит мне на ум, - написать собственный. Ёто должно быть довольно просто - 5-10 строк. ¬згл¤ните на это создание пользовательских помощников Html Helpers Mvc .


0

—тив —андерсон представил простую реализацию, котора¤ может делать то, что вы ищете. я недавно начал использовать его сам; он не идеален, но он действительно работает.   BeginCollectionItemсожалению, вам нужно немного намазать магию, чтобы использовать его метод; я пытаюсь обходить это самосто¤тельно.


0

ƒругой вариант - переопределить атрибут id следующим образом:

@Html.TextBoxFor(m => m.Name, new { id = @guid })

C #, asp.net-MVC, editorfor, asp.net-MVC-шаблоны,
Похожие вопросы