2012-03-13 34 views
3

我花了大約3個小時來確定爲什麼發生以下(解釋過的)錯誤;最後我確定這是一個mvc錯誤。我想問你的意見。使用EditorTemplate時出現id和name錯誤

我創建了一個編輯器模板,並將其放在〜/ Shared/EditorTemplates文件夾下。我仔細地使用文件名與類型名稱相同(因爲我不想用「@ Html.EditorFor」輔助方法使用第二個參數)。因此編輯器模板工作正常:除了回發;我肯定無法從模型中獲取值,因爲模型始終爲空。我試圖改變輸入的名稱,並仔細選擇,並做了回發:它工作正常。

所以;問題是:當我使用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循環的editortemplate &外視圖的內部,使用編輯器模板只爲單數項改變了我的模板,更容易之一。它的工作。因此,我使用反射器對mvc3上的模板工作做了一個小調查;我發現的bug,我想:

問題是由System.Web.Mvc.TemplateInfo類的公共字符串GetFullHtmlFieldName(字符串partialFieldName)方法,該方法是使用System.Web.Mvc.Html.SelectExtensions類的私有靜態MvcHtmlString引起SelectInternal(此HtmlHelper htmlHelper,字符串optionLabel,字符串名稱,IEnumerable selectList,bool allowMultiple,IDictionary htmlAttributes)方法。 因此,無論何時我們在一個foreach中使用@ Html.DropDownListFor(/ blah blah /),或者在EditorTemplate中使用for循環,我們都會得到該錯誤。

我也想下面爲您展示bug的代碼,以澄清:

// 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); 

那麼,你有什麼想法?

回答

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> 
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; 
} 

達林季米特洛夫建議使用

@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> 

一個模型編輯器代碼內?

相關問題