这种行为让我对我的理智感到好奇.
我有一个表单有两个接受输入的地方,我们称之为ValueA和ValueB.用户可以在任何一个和表单提交中输入值.
<div id="MyUpdateTarget"> <% using (Ajax.BeginForm("MyControllerAction",new AjaxOptions { UpdateTargetId = "MyUpdateTarget" })) { %> <%=Html.TextBox("ValueA",Model.ValueA,new Dictionary<string,object> { { "onchange","$('#SubmitButton').click(); return false;" },}) %> <%=Html.TextBox("ValueB",Model.ValueB,}) %> <input id="SubmitButton" type="submit" value="Save" style="display: none;" /> <% } %> </div>
Controller Action看起来像这样:
public ActionResult MyControllerAction(Myviewmodel viewmodel) {
//做一些其他的事……
return PartialView("MyPartialView",viewmodel); }
viewmodel就是这样的:
public class Myviewmodel { private int _valueA; private int _valueB; public int ValueA { get { return _valueA; } set { if (value > 0) { ValueB = 0; } _valueA = value; } } public int ValueB { get { return _valueB; } set { if (value > 0) { ValueA = 0; } _valueB = value; } } }
现在,意想不到的一块.假设页面最初加载而ValueB的值为7.用户将ValueA更改为5并且表单提交.我可以在控制器操作中放置一个断点,并在viewmodel参数中查看这两个值.此时,ValueA为5,ValueB为0(由于ValueA的设置).该操作将viewmodel作为PartialView的一部分返回.回到局部,我可以在Html.TextBox(“ValueB”,…)行上放置一个断点,看看ValueB确实为0.但是当表单渲染到浏览器时,ValueB仍然有一个这是我被困的地方.我甚至将Update目标更改为另一个div,以便部分只是吐出一个完全不同的形式,但它仍然具有原始值7,即使我通过调试看到值为0从0返回控制器.
有什么我想念的吗?
解决方法
以下是文本框的MVC源代码:
string attemptedValue = (string)htmlHelper.GetModelStateValue(name,typeof(string)); tagBuilder.MergeAttribute("value",attemptedValue ?? ((useViewData) ? htmlHelper.EvalString(name) : valueParameter**),isExplicitValue); break;
和GetModelStateValue()的代码
internal object GetModelStateValue(string key,Type destinationType) { ModelState modelState; if (ViewData.ModelState.TryGetValue(key,out modelState)) { if (modelState.Value != null) { return modelState.Value.ConvertTo(destinationType,null /* culture */); } } return null; }
因此,Html“Helper”通过匹配ViewData.ModalState中的名称来查找文本框值,如果它在ModelState字典中,它会完全忽略您提供的值.
所以if(value> 0){ValueA = 0;无关紧要,因为如果名称匹配,它将使用ModelState中的已发布值.
我修复此问题的方法是在视图呈现某些我希望在视图模型中混淆的值之前吹掉ModalState.这是我用过的一些代码:
public static void SanitizeWildcards( Controller controller,params string[] filterStrings ) { foreach( var filterString in filterStrings ) { var modelState = controller.ModelState; ModelState modelStateValue; if( modelState.TryGetValue(filterString,out controller.ModelState.SetModelValue(filterString,new ValueProviderResult("","",null)); } }