如何生产出MVC HTML编辑器模板非顺序preFIX收集指标? [英] How to produce non-sequential prefix collection indices with MVC HTML Editor templates?
问题描述
以下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屋!