id&;使用EditorTemplate时出现名称错误

本文关键字:错误 EditorTemplate amp 使用 id | 更新日期: 2023-09-27 18:27:30

我花了大约3个小时才确定发生以下(解释的)错误的原因;最后我确信这是一个mvc错误。我想听听你的意见。

我已经创建了一个编辑器模板,并将其放在~/Shared/EditorTemplates文件夹下。我小心地使用了与类型名相等的文件名(因为我不想将第二个参数与"@Html.EditorFor"helper方法一起使用)。结果编辑器模板运行良好:除了回发;我无法从模型中获取值,因为模型总是空的。我试着更改id&输入和选择的名称很仔细,并做了回复:它工作得很好。

所以;问题是:当我使用editorTemplate时,它给出了"Question.[0].QuestionContext"作为名称,"Question__0_QuestionContext"作为输入和选择的id;然而,我期望"Question[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&在视图内部,并且仅对单个项使用编辑器模板。它奏效了。所以我做了一个小的调查,通过使用反射器模板是如何在mvc3上工作的;我发现了错误,我想:

该问题是由System.Web.Mvc.TemplateInfo类的公共字符串GetFullHtmlFieldName(字符串partialFieldName)方法引起的,该方法由System.Web.Myvc.Html.SelectExtensions类的私有静态MvcHtmlString SelectInternal(此HtmlHelper HtmlHelper、字符串optionLabel、字符串名称、IEnumerable selectList、bool allowMultiple、IDictionary htmlAttributes)方法使用。因此,每当我们在foreach或EditorTemplate中的for循环中使用@Html.DropDownListFor(/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);

那么,你有什么想法?

id&;使用EditorTemplate时出现名称错误

然后我意识到我在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>

我有更复杂的渲染问题,结果相同:

而不是得到

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确实应该考虑索引器

"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()

但是,如何在模型编辑器中生成值为"%Index%"的隐藏输入"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>