2012-01-17 21 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