如何生产出MVC HTML编辑器模板非顺序preFIX收集指标? [英] How to produce non-sequential prefix collection indices with MVC HTML Editor templates?

查看:137
本文介绍了如何生产出MVC HTML编辑器模板非顺序preFIX收集指标?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下code已被剥夺了很多,但基本上是我要实现的是如下:

The following code has been stripped down a lot, but basically what I'm looking to achieve is as follows:

我希望能够编辑问题和他们的回答含选择,同时能够动态地从网页添加/删除问题/答案选择。理想的是,我的项目HtmlField preFIX将是不连续的,但Html.EditorFor()使用顺序索引

I'd like to able to edit Questions and their containing Answer Choices, while being able to dynamically add/remove Questions/Answer Choices from the page. Ideally, the HtmlFieldPrefix for my items would be non-sequential, but Html.EditorFor() uses a sequential index.

我有一个问题视图模型包含答案选项的IEnumerable

I have a Question ViewModel that contains an IEnumerable of Answer Choices:

public class QuestionViewModel
{
    public int QuestionId { get; set; }
    public IEnumerable<AnswerChoiceViewModel> AnswerChoices { get; set; }
}

在我的问题的局部视图(Question.ascx),我有这样的:

In my Question partial view (Question.ascx), I have this:

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

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

和应答选择编辑模板(AnswerChoiceViewModel.ascx):

And the Answer Choice editor template (AnswerChoiceViewModel.ascx):

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

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

当我渲染Question.ascx,输出将如下所示:

When I render Question.ascx, the output will look as follows:

<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" />

我想知道的是我能提供给EditorFor自定义的GUID索引,使页面会使这样的:

What I want to know is how I can provide EditorFor a custom GUID index so that the page would render like this:

<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" />

我已经写一个辅助方法,将得到当前上下文的preFIX索引,并将其存储在一个隐藏的的.index字段,以便非连续索引可以正确绑定。只是想知道EditorFor是如何分配的指标,这样我可以重写它(或任何其它工作液)。

I have already written a helper method that will get the prefix index of the current context and store it in a hidden ".Index" field so that non-sequential indices can be bound correctly. Just want to know how EditorFor is assigning the indexes so that I can override it (or any other working solution).

推荐答案

虽然以前我解决这个问题,跑进从S.桑德森后(Knockoutjs的作者),他描述和解决类似的问题。我用自己的code的部分,并试图修改它来满足我的需求。我把下面的code在某些类(exapmle:Helpers.cs),添加命名空间在web.config中

While ago I tackled with this problem and ran into a post from S. Sanderson(creator of Knockoutjs) where he described and solved similar problem. I used portions of his code and tried to modify it to suit my needs. I put the code below in some class (exapmle: Helpers.cs), add the namespace in web.config.

    #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

在你可以有EditorTemplate或部分类似这样

After you can have EditorTemplate or partial like this

@using (Html.BeginCollectionItem("AnswerChoices"))
{
@Html.HiddenFor(m => m.AnswerChoiceId)
@Html.TextBoxFor(m => m.Name)
}

和通过您的列表呈现模板枚举(部分)。

And enumerate through your list rendering template(partial).

这篇关于如何生产出MVC HTML编辑器模板非顺序preFIX收集指标?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆