c# - 如果发布后模型中的值发生变化,表单仍显示旧值

标签 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>

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 并且表单提交。我可以在 Controller 操作中放置一个断点,并在 viewModel 参数中查看这两个值。此时,ValueA 为 5,ValueB 为 0(由于 ValueA 的设置)。该操作将 viewModel 作为 PartialView 的一部分返回。回到局部,我可以在 Html.TextBox("ValueB", Model.ValueB, ...) 行上放置一个断点,然后看到 ValueB 确实是 0。但是当表单呈现给浏览器时,ValueB 仍然有一个值为 7。这就是我被困的地方。我什至将 Update 目标更改为不同的 div,因此部分只是在完全不同的地方吐出形式,但它仍然具有原始值 7,即使我通过调试看到该值是 0 从 Controller 。

有什么我想念的吗?

最佳答案

这是文本框的 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 中发布的值。

我解决这个问题的方法是在 View 呈现我想在我的 View 模型中弄乱的某些值之前吹走 ModelState。这是我用过的一些代码:

    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));
        }
    }

关于c# - 如果发布后模型中的值发生变化,表单仍显示旧值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1848586/

相关文章:

c# - [ThreadStatic] 的使用与异步代码不一致吗?

javascript - form.serialize() 不起作用

PHP Ajax 查询 - 将多个文件上传为 blob

c# - 在 ASP.net 5 MVC 6 中,如何在不同的命名空间中使用相同的 Controller 名称

javascript - 在 ASP.NET MVC 中创建 _layout 和 View 之间可用的 jQuery "object"

c# - 如何在大型项目中进行单元测试

C# 双缓冲?

c# - 单击链接时执行客户端脚本

c# - 项目安装程序无法打开另一台计算机上的数据库。我的项目是带有 sqlite 数据库连接的 C# Windows 应用程序

javascript - jQuery 'on' 事件在 'load' 事件后不起作用