我花了大约3个小时来确定为什么会发生以下(解释)错误;最后我确定这是一个mvc错误。我想问你的意见。
我已经创建了一个编辑器模板并将其放在〜/ Shared / EditorTemplates文件夹下。我仔细使用文件名与类型名称相同(因为我不想使用第二个参数和“@ Html.EditorFor”辅助方法)。结果编辑器模板工作正常:除了回发;我绝对无法从模型中获取值,因为模型始终为null。我试图改变id&输入和选择的名称仔细并做了回发:它工作正常。
因此;问题是:当我使用editorTemplate时,它将“Question。[0] .QuestionContext”作为名称,将“Question__0_QuestionContext”作为输入和选择的id;但我期待“问题[0] .QuestionContext”作为名称,“Question_0__QuestionContext”作为id。
然后我意识到我在EditorTemplate中使用@foreach。然后我切换回@for但没有改变。您可以在下面找到以下模板:
@using DenemeMvc3Application3.Helpers;
@model DenemeMvc3Application3.Controllers.LocalizedNameViewModels
<table>
<thead>
<tr>
<td>@Html.LabelFor(modelItem => modelItem.ElementAtOrDefault(0).LanguageDropDownList)</td>
<td>@Html.LabelFor(modelItem => modelItem.ElementAtOrDefault(0).Value)</td>
</tr>
</thead>
<tbody>
@for (int index = 0; index < Model.Count; index++)
{
@Html.EditorFor(modelItem => modelItem[index])
}
</tbody>
</table>
所以我通过在editortemplate&amp;之外声明foreach循环,将模板更改为更简单的模板。在视图内部并仅使用编辑器模板用于单个项目。它奏效了。因此,我通过使用反射器对mvc3上的模板工作进行了一个小小的调查;我发现了我想的错误:
问题是由System.Web.Mvc.TemplateInfo类的公共字符串GetFullHtmlFieldName(字符串partialFieldName)方法引起的,该方法由System.Web.Mvc.Html.SelectExtensions类的私有静态MvcHtmlString SelectInternal使用(此HtmlHelper htmlHelper,字符串optionLabel,字符串名称,IEnumerable selectList,bool allowMultiple,IDictionary htmlAttributes)方法。 因此,每当我们在foreach或在EditorTemplate中的for循环中使用@ Html.DropDownListFor(/ blah blah /)时,我们都会收到错误。
我还想向您展示下面的错误代码以澄清:
// TemplateInfo method
public string GetFullHtmlFieldName(string partialFieldName)
{
/*Here's the extra dot: causing the error.*/
return (this.HtmlFieldPrefix + "." + (partialFieldName ?? string.Empty)).Trim(new char[] { '.' });
}
// SelectExtensions method
private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, string optionLabel, string name, IEnumerable<SelectListItem> selectList, bool allowMultiple, IDictionary<string, object> htmlAttributes)
{
/* blah blah */
string fullHtmlFieldName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
/* blah blah */
}
// SelectExtensions method -> @Html.DropDownListFor
private static MvcHtmlString DropDownListHelper(HtmlHelper htmlHelper, string expression, IEnumerable<SelectListItem> selectList, string optionLabel, IDictionary<string, object> htmlAttributes)
{
return htmlHelper.SelectInternal(optionLabel, expression, selectList, false, htmlAttributes);
那么,你有什么想法?
答案 0 :(得分:3)
然后我意识到我在EditorTemplate中使用@foreach。 然后我切换回@for但没有改变。
如何摆脱所有循环,简单地说:
@model IEnumerable<FooViewModel>
<table>
<thead>
<tr>
<td>@Html.LabelFor(modelItem => modelItem.ElementAtOrDefault(0).LanguageDropDownList)</td>
<td>@Html.LabelFor(modelItem => modelItem.ElementAtOrDefault(0).Value)</td>
</tr>
</thead>
<tbody>
@Html.EditorForModel()
</tbody>
</table>
好多了?没有循环和正确的名称和ID。它是ASP.NET MVC,它将自动为模型集合的每个元素呈现编辑器模板。
和相应的编辑器模板(~/Views/Shared/EditorTemplates/FooViewModel.cshtml
):
@model FooViewModel
<tr>
<td>@Html.EditorFor(x => x.SomeProperty)</td>
<td>@Html.EditorFor(x => x.SomeOtherProperty)</td>
</tr>
答案 1 :(得分:0)
我有更复杂的渲染问题,结果相同:
而不是
xxxx.yyy.zzz.MyCollection[%index%]
一个人得到:
xxxx.yyy.zzz.MyCollection.[%index%]
我认为最初的MVC方法:
public string GetFullHtmlFieldName(string partialFieldName)
{
/*Here's the extra dot: causing the error.*/
return (this.HtmlFieldPrefix + "." + (partialFieldName ?? string.Empty)).Trim(new char[] { '.' });
}
并不完美,因为partialFieldName参数的值可以是例如“[0] .AAA”
ASP.NET MVC CodePlex上已存在此问题:
GetFullHtmlFieldName really should take indexers into account
“FIX”就可以:
public static IHtmlString EnsureCorrectCollectionName(this HtmlHelper htmlHelper, string partialName, IHtmlString somethingToBeRendered)
{
//TODO: check http://aspnet.codeplex.com/workitem/5495 to remove this fix
if (partialName.StartsWith("["))
{
string fullHtmlFieldName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(partialName);
if (fullHtmlFieldName.EndsWith("." + partialName))
{
string htmlCode = somethingToBeRendered.ToHtmlString();
string nameAttribute = "name=\"" + fullHtmlFieldName + "\"";
var p = htmlCode.IndexOf(nameAttribute);
int endIndex = p + nameAttribute.Length - partialName.Length - 2;
var correctedHtmlCodeStart = htmlCode.Substring(0, endIndex);
var correctedHtmlCodeEnd = htmlCode.Substring(endIndex+1);
return new HtmlString(correctedHtmlCodeStart + correctedHtmlCodeEnd);
}
}
return somethingToBeRendered;
}
Darin Dimitrov建议使用
@Html.EditorForModel()
但是如何在模型编辑器代码中生成右隐藏输入“xxx.yyy.zzz.MyCollection.Index”,其值为“%%%”
@model FooViewModel
<tr>
<td>@Html.EditorFor(x => x.SomeProperty)</td>@*rendered as name="xxx.yyy.zzz.MyCollection[%index%].SomeProperty"*@
<td>
@Html.EditorFor(x => x.SomeOtherProperty)@*rendered as name="xxx.yyy.zzz.MyCollection[%index%].SomeOtherProperty"*@
<input type="hidden" name="xxx.yyy.zzz.MyCollection.Index" value="@(%index%)"/>
</td>
</tr>