ASP.Net MVC Html.HiddenFor具有错误的值
我在我的项目中使用MVC 3,我看到一个非常奇怪的行为。
我试图为我的模型上的特定值创build一个隐藏的字段,问题是,由于某种原因,字段上设置的值不对应于模型中的值。
例如
我有这个代码,只是作为一个testing:
<%:Html.Hidden("Step2", Model.Step) %> <%:Html.HiddenFor(m => m.Step) %>
我会认为这两个隐藏的领域将具有相同的价值。 我所做的是在第一次显示视图时将值设置为1,然后在提交之后将模型字段的值增加1。
所以,我第一次渲染页面时,两个控件的值都是1,但是第二次渲染的值是这些:
<input id="Step2" name="Step2" type="hidden" value="2" /> <input id="Step" name="Step" type="hidden" value="1" />
正如你所看到的,第一个值是正确的,但第二个值似乎是第一次显示视图相同。
我错过了什么? *对于Html帮助者以某种方式caching值? 如果是这样,我怎么能禁用这个caching?
谢谢你的帮助。
这是正常的,这是HTML助手如何工作。 他们首先使用POST请求的值,然后是模型中的值。 这意味着即使您在控制器操作中修改模型的值(如果POST请求中存在相同的variables),您的修改也将被忽略,并且将使用POST的值。
一种可能的解决方法是从试图修改该值的控制器操作中的模型状态中删除此值:
// remove the Step variable from the model state // if you want the changes in the model to be // taken into account ModelState.Remove("Step"); model.Step = 2;
另一种可能性是编写一个自定义HTML助手,它总是使用模型的值并忽略POST值。
还有一种可能性:
<input type="hidden" name="Step" value="<%: Model.Step %>" />
在编写向导时,我遇到了同样的问题,该向导在每一步都显示了较大模型的不同部分。
来自“步骤1”的数据和/或错误将与“步骤2”等混淆,直到我终于认识到ModelState是“责怪”的。
这是我简单的解决scheme:
if (oldPageIndex != newPageIndex) ModelState.Clear(); // <-- solution return View(model[newPageIndex]);
此代码将无法正常工作
// remove the Step variable from the model state // if you want the changes in the model to be // taken into account ModelState.Remove("Step"); model.Step = 2;
…因为HiddenFor总是(!)从模型状态读取而不是模型本身。 如果找不到“Step”键,则会产生该variablestypes的默认值,在这种情况下将为0
这是解决scheme。 我自己写的,但不介意分享,因为我看到很多人都在用这个顽皮的HiddenFor帮手挣扎。
public static class CustomExtensions { public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) { ReplacePropertyState(htmlHelper, expression); return htmlHelper.HiddenFor(expression); } public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes) { ReplacePropertyState(htmlHelper, expression); return htmlHelper.HiddenFor(expression, htmlAttributes); } public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes) { ReplacePropertyState(htmlHelper, expression); return htmlHelper.HiddenFor(expression, htmlAttributes); } private static void ReplacePropertyState<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) { string text = ExpressionHelper.GetExpressionText(expression); string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(text); ModelStateDictionary modelState = htmlHelper.ViewContext.ViewData.ModelState; ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); if (modelState.ContainsKey(fullName)) { ValueProviderResult currentValue = modelState[fullName].Value; modelState[fullName].Value = new ValueProviderResult(metadata.Model, Convert.ToString(metadata.Model), currentValue.Culture); } else { modelState[fullName] = new ModelState { Value = new ValueProviderResult(metadata.Model, Convert.ToString(metadata.Model), CultureInfo.CurrentUICulture) }; } } }
然后你就像往常一样从你内部使用视图:
@Html.HiddenFor2(m => m.Id)
值得一提的是它也适用于collections。