8

この振る舞いは、私の正気について不思議に思っています。

入力を受け入れる2つの場所があるフォームがあります。それらを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の設定による)。このアクションは、PartialViewの一部としてviewModelを返します。部分に戻ると、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ディクショナリにある場合は、指定した値を完全に無視します。

つまり、if(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..これは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 に答える
0

@jfarが述べたように、コントローラーのModelStateから変数を削除するとうまくいきます。ただし、より少ないコードでそれを行うことができます(少なくとも最近は)。

ModelState.Remove("ValueA");
于 2013-06-13T15:30:49.543 に答える