2012-01-17 54 views
0

我已經在HtmlHelper上構建了一個CheckBoxListFor擴展,這要歸功於這個美妙的答案http://bit.ly/Aevcea(代碼如下),但是我發現它不按預期發佈。MVC CheckBoxListFor不按預期發佈

我的表單基於一個模型組,其中包含(其他屬性)string Name和int [] PersonIDs。

的CheckBoxListFor呈現這樣的事情:

<ul> 
    <li><input type="checkbox" name="PersonIDs" value="1" id="PersonIDs_1" /></li> 
    <li><input type="checkbox" name="PersonIDs" value="2" id="PersonIDs_2" /></li> 
</ul> 

我的控制有一個編輯(組羣)的方法來處理提交此表。但是,提交後,我發現group.PersonIDs爲空。雖然有一個Request.Form [「PersonIDs」]設置爲選定的值(例如,如果同時選中上述兩項,則爲「1,2」)。另外,如果我添加另一個參數到我的編輯方法(int [] PersonIDs),那麼到達與預期的內容(選定的ID)。

任何人都可以解釋我做錯了什麼?我的觀點的相關位看起來像這樣(去掉了多餘位):

@Html.TextBoxFor(m => m.Group.Name) 
@Html.CheckBoxListFor(m => m.Group.PersonIDs, Model.MultiSelectListOfAllPeople) 

注意,在我的編輯方法組參數不回來與名稱根據形式設置。

只是爲了完整性,這裏是我的CheckBoxListFor延長的全身:

public static MvcHtmlString CheckBoxListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, IEnumerable<TProperty>>> expression, MultiSelectList multiSelectList, object htmlAttributes = null) 
{ 
    //Derive property name for checkbox name 
    MemberExpression body = expression.Body as MemberExpression; 
    string propertyName = body.Member.Name; 

    //Get currently select values from the ViewData model 
    IEnumerable<TProperty> list = expression.Compile().Invoke(htmlHelper.ViewData.Model); 

    //Convert selected value list to a List<string> for easy manipulation 
    List<string> selectedValues = new List<string>(); 

    if (list != null) 
    { 
     selectedValues = new List<TProperty>(list).ConvertAll<string>(delegate(TProperty i) { return i.ToString(); }); 
    } 

    //Create div 
    TagBuilder wrapper = new TagBuilder("ul"); 
    wrapper.AddCssClass("clearfix"); 
    wrapper.MergeAttributes(new RouteValueDictionary(htmlAttributes), true); 

    //Add checkboxes 
    foreach (SelectListItem item in multiSelectList) 
    { 
     wrapper.InnerHtml += String.Format("<li><input type=\"checkbox\" name=\"{0}\" id=\"{0}_{1}\" " + 
              "value=\"{1}\" {2} /><label for=\"{0}_{1}\">{3}</label></li>", 
              propertyName, 
              item.Value, 
              selectedValues.Contains(item.Value) ? "checked=\"checked\"" : "", 
              item.Text); 
    } 

    return MvcHtmlString.Create(wrapper.ToString()); 
} 

回答

1

OK,問題是,需要CheckBoxListFor擴展呈現控件名稱Group.PersonIDs,而不是簡單PersonIDs。表單綁定到一個對象,該對象本身是視圖模型的子屬性。我已經很快適應了我的CheckBoxListFor方法,但會感激地接受更優雅的解決方案!我傳遞一個額外的布爾參數includeDeclaringType來告訴它是否在ID中包含聲明類型的名稱。不知道這是否可以用任何其他方式推斷..?

public static MvcHtmlString CheckBoxListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, IEnumerable<TProperty>>> expression, MultiSelectList multiSelectList, bool includeDeclaringType, object htmlAttributes = null) 
    { 
     //Derive property name for checkbox name 
     MemberExpression body = expression.Body as MemberExpression; 
     string declaringTypeName = body.Member.DeclaringType.Name; 
     string propertyName = body.Member.Name; 

     //Get currently select values from the ViewData model 
     IEnumerable<TProperty> list = expression.Compile().Invoke(htmlHelper.ViewData.Model); 

     //Convert selected value list to a List<string> for easy manipulation 
     List<string> selectedValues = new List<string>(); 

     if (list != null) 
     { 
      selectedValues = new List<TProperty>(list).ConvertAll<string>(delegate(TProperty i) { return i.ToString(); }); 
     } 

     //Create div 
     TagBuilder wrapper = new TagBuilder("ul"); 
     wrapper.AddCssClass("clearfix"); 
     wrapper.MergeAttributes(new RouteValueDictionary(htmlAttributes), true); 

     //Add checkboxes 
     foreach (SelectListItem item in multiSelectList) 
     { 
      var name = string.Concat(
       includeDeclaringType ? string.Format("{0}.", declaringTypeName) : "", 
       propertyName 
      ); 

      var id = string.Concat(
       includeDeclaringType ? string.Format("{0}_", declaringTypeName) : "", 
       propertyName, 
       "_", 
       item.Value 
      ); 

      wrapper.InnerHtml += String.Format("<li><input type=\"checkbox\" name=\"{0}\" id=\"{1}\" " + 
               "value=\"{2}\" {3} /><label for=\"{1}\">{4}</label></li>", 
               name, 
               id, 
               item.Value, 
               selectedValues.Contains(item.Value) ? "checked=\"checked\"" : "", 
               item.Text); 
     } 

     return MvcHtmlString.Create(wrapper.ToString()); 
    } 
0

您還可以使用ExpressionHelper.GetExpressionText方法,它會爲你生成正確的輸入名稱:

var expressionText = ExpressionHelper.GetExpressionText(expression); 

wrapper.InnerHtml += 
     string.Format("<li><input type=\"checkbox\" name=\"{0}" id=\"{0}_{1}\" " + 
         "value=\"{1}\" {2} /><label for=\"{0}_{1}\">{3}</label></li>", 
         expressionText, 
         item.Value, 
         selectedValues.Contains(item.Value) ? "checked=\"checked\"" : "", 
         item.Text); 
+0

感謝@nativehr - 我真的不能標記這個作爲回答,但它確實有用的信息。 – getsetcode 2013-05-10 08:41:32