【问题标题】:ModelState binding custom array of checkboxesModelState 绑定自定义复选框数组
【发布时间】:2014-01-03 17:24:41
【问题描述】:

ViewModel 绑定正在工作,传回编辑控制器的对象包含正确的值,这是一个选定选项的列表。但是,ModelState 绑定不起作用,模型状态 AttemptedValues 存在,但没有被重新加载到字段中。

我有一个具有以下属性的模型

class Model
{
    public List<string> AvailableValues { get; set; }
    public List<string> SelectedValues { get; set; }
}

但在我看来,我有一些分类,所以我不能直接进行 foreach。

foreach (var category in CatgoryList.Categories)
{
    foreach (var available in Model.AvailableValues.Where(x => category.AvailableValues.Contains(x))
    {
        var check = Model.SelectedValues!= null && Model.SelectedValues.Contains(available.Id);
        check &= (ViewData.ModelState["SelectedValues"] != null) && ViewData.ModelState["SelectedValues"].Value.AttemptedValue.Contains(available.Id);
        <input type="checkbox" name="SelectedValues" id="available.Id" value="available.Id" checked="@check"/>@available.FriendlyName<br>
    }
}

ModelState 确实包含上一篇文章中的 SelectedValues,但它不会自动绑定,因为我有一个用于复选框的自定义字段。

这段代码很臭

有没有更好的方法来从尝试值中加载数据

编辑:

好的,所以我的问题不够清楚,让我澄清一下。

在验证时,如果出现错误,我将重新调整相同的视图。 modelstate 保存先前在 ModelState["field"].Value.AttemptedValue 中输入的值。 使用帮助器、TextboxFor、CheckboxFor 等创建的字段会自动填充这些值。

但是,当使用普通反射进行复选框绑定时,只有选中复选框的值会在传递回控制器的数据对象中返回。这意味着我没有使用从 ModelState 中填充值的逻辑。

我所做的是自己在模型状态中挖掘尝试的值,因为它们确实存在于字段名称“SelectedValues”下。但我必须手动应用它们。那里的值看起来像这样。

ModelState["SelectedValues"] = "Value1;Value2;Value4"

有没有更好的方法来从模型状态下的尝试值加载数据。

【问题讨论】:

  • 你认为ModelState 是什么?您在视图中使用它的方式没有意义。此外,诸如绑定之类的术语在 asp.net MVC 中具有非常特定的含义。没有 ViewModel 绑定之类的东西,“自动绑定”没有任何意义。
  • 如果我的答案不清楚,请跟进,或者如果没问题,请接受作为答案
  • @GregEnnis 不,对不起。这没有帮助。
  • 通常当有人发布“这段代码很臭”时,他们正在寻求如何改进它的建议。很抱歉我浪费了你的时间。祝你好运

标签: asp.net-mvc modelstate html.checkbox


【解决方案1】:

我在这里看到的主要“气味”(使用您的术语)是嵌套 foreach 中的代码直接写在您的视图中 (*.cshtml),但这种复杂性的代码应该在您的 @987654322 中@ 行动。

您应该在控制器中计算并生成视图所需的所有数据,然后使用 Model 将这些数据传递给视图(看起来您已经这样做了),您也可以使用 ViewBag传递模型中未包含的其他数据。然后视图只负责生成 HTML。

这是我在您的代码中看到的另一个问题 - 您正在引用 ViewData.ModelState,这在视图中是非常不寻常的。在决定渲染哪个视图之前,应该在控制器中检查 ModelState。

看起来您可能只是通过 ViewData.ModelState 传递数据,而实际上应该通过 ViewData/ViewBag 传递数据。

您可以阅读有关将数据传递到视图 here 的更多信息。

【讨论】:

  • 将数据传递给视图没有问题。数据被传递到视图并在发布表单时返回到控制器就好了。未加载的是来自 ModelState 的数据。 ModelState 包含验证错误以及 Attempted 值。如果您想在字段上显示错误,但又不想丢失用户所做的进度,则必须从 ModelState 中获取值。
【解决方案2】:

好的,基本上,我找不到任何可以为我做这件事的东西。默认的 Html 辅助方法只是不涵盖这种情况。

所以,我写了一个扩展方法。

基本上,它使用您发送给它的表达式从模型中提取枚举器,就像任何其他帮助器一样,但您也可以发送列表中要构建复选框的条目。

它最终看起来像这样。

@Html.CheckboxListEntryFor(x => x.SelectedEntries, AvailableEntries[i].Id)

该方法执行以下操作

  1. 获取列表的 propertyInfo 并检查所选条目是否包含值。
  2. 检查ModelState是否无效,如果无效,用modelstate条目覆盖检查值
  3. 构建一个html复选框,使用属性名作为复选框的名称和id,并根据前面的步骤设置checked。

    public static MvcHtmlString CheckboxListEntryFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression, string entryValue)
    {
        PropertyInfo info = GetPropertyInfo(typeof (TModel), expression);
        var enumerator = info.GetValue(htmlHelper.ViewData.Model);
        var check = enumerator != null && ((IList) enumerator).Contains(entryValue);
        if (!htmlHelper.ViewData.ModelState.IsValid)
        {
            check = htmlHelper.ViewData.ModelState[info.Name] != null &&
                htmlHelper.ViewData.ModelState[info.Name].Value.AttemptedValue.Contains(entryValue);
        }
    
        var fieldString = String.Format(
                          "<input type=\"checkbox\" name=\"{0}\" id =\"{1}\" value=\"{1}\"{2}/>",
                          info.Name, entryValue, check ? " checked=\"checked\"" : string.Empty);
    
        return MvcHtmlString.Create(fieldString);
    }
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多