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

时间:2012-03-13 07:26:38

标签: c# asp.net .net asp.net-mvc-3

我花了大约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);

那么,你有什么想法?

2 个答案:

答案 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>