我正在尝试建立一个HTML帮助器来创建复选框列表,该复选框将使用会话持久保存检查状态。它在大多数情况下都起作用,当您选中和取消选中各个复选框并单击提交时,会记住复选框状态。但是,如果您已选中并提交了复选框,然后返回并清除复选框,然后重新提交(当它们全部清除时)-似乎想记住最后的选择。这是我写的...
[HomeController]
public ActionResult Index()
{
TestViewModel tvm = new TestViewModel();
return View(tvm);
}
[HttpPost]
public ActionResult Index(TestViewModel viewModel)
{
viewModel.SessionCommit();
return View(viewModel);
}
[索引视图]
@model TestApp.Models.TestViewModel
@{
ViewBag.Title = "Index";
}
@using (Html.BeginForm())
{
<p>Checkboxes:</p>
@Html.CheckedListFor(x => x.SelectedItems, Model.CheckItems, Model.SelectedItems)
<input type="submit" name="Submit form" />
}
[TestViewModel]
// Simulate the checklist data source
public Dictionary<int, string> CheckItems
{
get
{
return new Dictionary<int, string>()
{
{1, "Item 1"},
{2, "Item 2"},
{3, "Item 3"},
{4, "Item 4"}
};
}
}
// Holds the checked list selections
public int[] SelectedItems { get; set; }
// Contructor
public TestViewModel()
{
SelectedItems = GetSessionIntArray("seld", new int[0] );
}
// Save selections to session
public void SessionCommit()
{
System.Web.HttpContext.Current.Session["seld"] = SelectedItems;
}
// Helper to get an int array from session
int[] GetSessionIntArray(string sessionVar, int[] defaultValue)
{
if (System.Web.HttpContext.Current.Session == null || System.Web.HttpContext.Current.Session[sessionVar] == null)
return defaultValue;
return (int[])System.Web.HttpContext.Current.Session[sessionVar];
}
[HTML帮手]
public static MvcHtmlString CheckedList(this HtmlHelper htmlHelper, string PropertyName, Dictionary<int, string> ListItems, int[] SelectedItemArray)
{
StringBuilder result = new StringBuilder();
foreach(var item in ListItems)
{
result.Append(@"<label>");
var builder = new TagBuilder("input");
builder.Attributes["type"] = "checkbox";
builder.Attributes["name"] = PropertyName;
builder.Attributes["id"] = PropertyName;
builder.Attributes["value"] = item.Key.ToString();
builder.Attributes["data-val"] = item.Key.ToString();
if (SelectedItemArray.Contains(item.Key))
builder.Attributes["checked"] = "checked";
result.Append(builder.ToString(TagRenderMode.SelfClosing));
result.AppendLine(string.Format(" {0}</label>", item.Value));
}
return MvcHtmlString.Create(result.ToString());
}
public static MvcHtmlString CheckedListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, Dictionary<int, string> ListItems, int[] SelectedItemArray)
{
var name = ExpressionHelper.GetExpressionText(expression);
var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
return CheckedList(htmlHelper, name, ListItems, SelectedItemArray);
}
我已经读过这个问题,我认为这可能与模型联编程序不知道何时未选中任何复选框有关,但是即使我已经阅读了该文章以及其他各种帖子,我也无法继续前进。
在一篇文章中,我看到一个隐藏字段通常与复选框结合使用,以传递复选框的“ false”状态,但是我无法使它与将多个复选框发布回单个属性一起使用。
谁能阐明这一点?
编辑:包括本文中突出显示的演示项目。希望这会帮助某人来帮助我!
您的主要问题以及取消选中所有项时“记住”先前选择的原因是,您的模型中有一个构造函数,该构造函数调用GetSessionIntArray()
获取上次提交表单时存储的值。在DefaultModelBinder
首先初始化模型(包括调用其默认构造方法),然后设置基于表单值的属性值的作品。在以下情况下
第1步:导航到Index()
方法
Session
,则SelectedItems
return by的值GetSessionIntArray()
是int[0]
,与中的任何值都不匹配CheckItems
,因此不会选中任何复选框。第2步:选中前2个复选框并提交。
DefaultModelBinder
初始化的新实例TestViewModel
,并调用构造函数。SelectedItems
再次是的值int[0]
(尚未添加任何内容Session
)。然后读取表单值,SelectedItems
现在int[1, 2]
的值为(选中的复选框的值)。在返回视图之前,将调用方法中的代码并将int[1, 2]
其添加到该代码中Session
。步骤3:取消选中所有复选框,然后再次提交。
Session
并且SelectedItems
is的值int[1,2]
。在DefaultModelBinder
读取表单值SelectedItems
,但有没有(未选中的复选框不提交值),所以没有什么设置和值SelectedItems
遗体int[1,2]
。然后,您返回视图,您的助手将根据以下值检查前两个复选框SelectedItems
您可以通过从模型中删除构造函数并修改扩展方法中的代码以进行测试来解决此问题 null
if (SelectedItemArray != null && SelectedItemArray.Contains(item.Key))
{
....
但是,您的实现还有其他问题,包括
您id
为每个复选框(您使用builder.Attributes["id"] = PropertyName;
)生成的重复属性都是无效的html。
builder.Attributes["data-val"] = item.Key.ToString();
是没有意义的(它产生data-val="1"
,data-val="1"
等)。假设您希望属性用于不打扰的客户端验证,则属性将为data-val="true" data-val-required="The SelectedItems field is required."
。但是,那么您将需要为错误消息关联一个占位符(由生成,@Html.ValidationMessageFor()
并且name
每个复选框的属性必须是不同的(即,使用索引器-name="[0].SelectedItems"
等)。
您使用属性的值进行绑定,但是正确的方法(所有内置扩展方法都使用该方法)是首先从获取值ModelState
,然后从获取值,ViewDataDictionary
如果没有找到值,最后获取实际模型属性。
var metadata = ModelMetadata.....
尽管应该使用,但您永远不会使用值(这样您就可以int[] SelectedItemArray
从方法中删除最后一个参数(),实际上是在重复的值expression
。
旁注:在您的情况下,隐藏字段的使用不适用。该CheckboxFor()
方法生成附加的隐藏输入,因为该方法绑定到bool
属性,并确保始终提交值。
我的建议是使用诸如MvcCheckBoxList之类的包(因为我有自己的扩展方法,所以我自己也没有尝试过),至少要等到您花一些时间研究MVC源代码以更好地了解如何创建HtmlHelper
扩展方法(对不起)如果听起来很刺耳)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句