8

这种行为让我怀疑我的理智..

我有一个表单,它有两个接受输入的地方,我们称它们为 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>

控制器动作如下所示:

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", Model.ValueB, ...) 行上放一个断点,看到 ValueB 确实为 0。但是当表单呈现给浏览器时,ValueB 仍然有一个值为 7。这就是我卡住的地方。我什至将 Update 目标更改为不同的 div,以便部分只是在某个完全不同的地方吐出表单,但它仍然具有原始值 7,

有什么我想念的吗?

4

4 回答 4

8

这是文本框的 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 字典中,它会完全忽略您提供的值。

所以如果 (value > 0) { ValueA = 0; } 没关系,因为如果名称匹配,它将使用 ModelState 中发布的值。

我解决这个问题的方法是在视图渲染某些我想在我的视图模型中弄乱的值之前吹掉 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));
        }
    }
于 2009-12-04T19:58:25.107 回答
8

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

ViewData.ModelState.Clear();
于 2010-11-09T13:01:10.190 回答
0

正如@jfar 提到的,从控制器中的 ModelState 中删除变量就可以了。不过,您可以用更少的代码来做到这一点(至少现在是这样)。

ModelState.Remove("ValueA");
于 2013-06-13T15:30:49.543 回答
0

谢谢jfar ..这是vb代码:

Sub CleanForm(ByVal ParamArray Fields() As String)
    Dim modelStateValue As ModelState = Nothing
    For Each Field In Fields
        If ModelState.TryGetValue(Field, modelStateValue) Then
            ModelState.SetModelValue(Field, New ValueProviderResult(Nothing, Nothing, Nothing))
        End If
    Next
End Sub
于 2010-07-18T14:50:53.940 回答