2012-03-13 2 views
3

次の(説明された)エラーが発生した原因を確認するのに約3時間かかりました。私はそれがmvcエラーだと確信しています。あなたの意見を聞きたい。EditorTemplateを使用しているときにIDと名前のエラーが発生しました

私はエディタテンプレートを作成し、〜/ Shared/EditorTemplatesフォルダの下に配置しました。そして私は注意深くファイル名を型名と同じにしました。なぜなら、 "@ Html.EditorFor"ヘルパーメソッドで2番目のパラメータを使いたくないからです。結果として、エディタテンプレートはうまくいきました。ポストバックを除いて。モデルが常にnullだったので、私はモデルから値を得ることはできませんでした。私は入力のID &の名前を変更しようと慎重に選択し、ポストバックをしました:それはうまくいきます。

So;問題は:私がeditorTemplateを使用すると、名前として "Question。[0] .QuestionContext"、入力と選択のIDとして "Question__0_QuestionContext"が与えられます。私は "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 &の外にforeachループを宣言し、唯一の特異項目のためのエディタのテンプレートを使って、簡単に一つに私のテンプレートを変更しました。そしてそれは働いた。そこで、リフレクタを使用してmvc3でテンプレートがどのように機能するかについて少し調べました。

この問題は、System.Web.Mvc.TemplateInfoクラスのパブリック文字列GetFullHtmlFieldName(string partialFieldName)メソッドによって発生します。このメソッドは、System.Web.Mvc.Html.SelectExtensionsクラスのプライベート静的MvcHtmlString SelectInternal(このHtmlHelper htmlHelper、文字列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); 

だから、あなたの考えは何ですか?

答えて

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%] 

1つを得るのは、取得します。

xxxx.yyy.zzz.MyCollection.[%index%] 

私は、元のMVCの方法だと思う:partialFieldNameパラメータの値は、例えばできるため

public string GetFullHtmlFieldName(string partialFieldName) 
{ 
    /*Here's the extra dot: causing the error.*/ 
    return (this.HtmlFieldPrefix + "." + (partialFieldName ?? string.Empty)).Trim(new char[] { '.' }); 
} 

が、完璧ではありません"[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() 

しかし、どのように、その後1は正しい値=「%インデックス%」

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

と入力「xxx.yyy.zzz.MyCollection.Index」隠されたモデルエディタのコード内で生成することができますか?