【问题标题】:id & name error when using an EditorTemplate使用 EditorTemplate 时出现 id & name 错误
【发布时间】:2012-03-29 14:36:21
【问题描述】:

我花了大约 3 个小时才确定为什么会发生以下(解释的)错误;最后我确定这是一个 mvc 错误。我想问问你的意见。

我创建了一个编辑器模板并将其放在 ~/Shared/EditorTemplates 文件夹下。而且我小心地使用文件名与类型名相等(因为我不想将第二个参数与“@Html.EditorFor”帮助方法一起使用)。结果编辑器模板工作正常:除了回发;我肯定无法从模型中获取值,因为模型始终为空。我尝试更改输入的 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>

所以我通过在编辑器模板之外和视图内部声明 foreach 循环并将编辑器模板仅用于单个项目,从而将我的模板更改为更简单的模板。它奏效了。因此,我对模板如何使用反射器在 mvc3 上工作进行了小调查;我发现了我认为的错误:

问题是由 System.Web.Mvc.Html.SelectExtensions 类的私有静态 MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, string optionLabel,字符串名称、IEnumerable selectList、bool allowMultiple、IDictionary htmlAttributes) 方法。 因此,每当我们在 EditorTemplate 中的 foreach 或 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);

那么,你的想法是什么?

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

      而不是得到

      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”,value="%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>
      

      ?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-05-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-01
        • 2015-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多