这种行为让我对自己的理智感到好奇。
我有一个表单有两个接受输入的地方,我们称之为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并且表单提交。我可以在控制器操作中放置一个断点,并在viewModel参数中查看这两个值。此时,ValueA为5,ValueB为0(由于ValueA的设置)。该操作将viewModel作为PartialView的一部分返回。回到局部,我可以在Html.TextBox(“ValueB”,Model.ValueB,...)行上放置一个断点,看看ValueB确实为0.但是当表单呈现给浏览器时,ValueB仍然有一个这是我被卡住的地方。我甚至将Update目标更改为另一个div,以便部分只是吐出一个完全不同的形式,但它仍然具有原始值7,即使我通过调试看到值为0从0返回控制器。
我有什么遗失的吗?
答案 0 :(得分:7)
以下是文本框的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 if(value&gt; 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));
}
}
答案 1 :(得分:6)
清除整个ModelState也可以解决问题:
ViewData.ModelState.Clear();
答案 2 :(得分: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
答案 3 :(得分:0)
正如@jfar所提到的,从控制器中的ModelState中删除变量就可以了。但是,你可以用更少的代码来实现这一目标(至少目前为止)。
ModelState.Remove("ValueA");