如果在帖子后模型中的值发生更改,则表单仍会显示旧值

Jon*_*ian 7 c# ajax asp.net-mvc http-post

这种行为让我对自己的理智感到好奇.

我有一个表单有两个接受输入的地方,我们称之为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, new Dictionary<string, object> {
                                                    { "onchange", "$('#SubmitButton').click(); return false;" },
       }) %>
  <input id="SubmitButton" type="submit" value="Save" style="display: none;" />
 <% } %>
</div>
Run Code Online (Sandbox Code Playgroud)

Controller Action如下所示:

public ActionResult MyControllerAction(MyViewModel viewModel)
{
Run Code Online (Sandbox Code Playgroud)

//做一些其他的事......

 return PartialView("MyPartialView", viewModel);
}
Run Code Online (Sandbox Code Playgroud)

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;
  }
 }
}
Run Code Online (Sandbox Code Playgroud)

现在,意想不到的一块.假设页面最初加载而ValueB的值为7.用户将ValueA更改为5并且表单提交.我可以在控制器操作中放置一个断点,并在viewModel参数中查看这两个值.此时,ValueA为5,ValueB为0(由于ValueA的设置).该操作将viewModel作为PartialView的一部分返回.回到局部,我可以在Html.TextBox("ValueB",Model.ValueB,...)行上放置一个断点,看看ValueB确实为0.但是当表单呈现给浏览器时,ValueB仍然有一个这是我被卡住的地方.我甚至将Update目标更改为另一个div,以便部分只是吐出一个完全不同的形式,但它仍然具有原始值7,即使我通过调试看到值为0从0返回控制器.

有什么我想念的吗?

Joh*_*ell 7

以下是文本框的MVC源代码:

     string attemptedValue = (string)htmlHelper.GetModelStateValue(name, typeof(string));
                tagBuilder.MergeAttribute("value", attemptedValue ?? ((useViewData) ? htmlHelper.EvalString(name) : valueParameter**), isExplicitValue);
                break;
Run Code Online (Sandbox Code Playgroud)

和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;
    }
Run Code Online (Sandbox Code Playgroud)

那么,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));
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 感谢 jfar 的洞察力!根据您的回复,我放弃了使用 html 输入的文本框助手。我的表单上只有两个输入需要这种行为,所以为了简单起见,我不必遍历 ModelState 字典。您的帖子非常有见地,并引导我找到了解决方案,再次感谢! (2认同)

ran*_*sen 6

清除整个ModelState也可以解决这个问题:

ViewData.ModelState.Clear();
Run Code Online (Sandbox Code Playgroud)