7


2

投稿後にモデルで値が変更されても、フォームには古い値が表示されます

この振る舞いは、私が私の正気について疑問に思うようにしています。

入力を受け付ける2つの場所があるフォームがあります。ValueAとValueBと呼びましょう。 ユーザーはどちらかに値を入力して、フォームを送信できます。

 <% using (Ajax.BeginForm("MyControllerAction", new AjaxOptions { UpdateTargetId = "MyUpdateTarget" })) { %>
  <%=Html.TextBox("ValueA", Model.ValueA, new Dictionary {
                                                    { "onchange", "$('#SubmitButton').click(); return false;" },
       }) %>
  <%=Html.TextBox("ValueB", Model.ValueB, new Dictionary {
                                                    { "onchange", "$('#SubmitButton').click(); return false;" },
       }) %>

 <% } %>

コントローラアクションは次のようになります。

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に変更したため、パーシャルはまったく別の場所にフォームを吐き出しますが、値が0であることをデバッグで確認しても、元の値は7です。コントローラ。

足りないものはありますか。

4 Answer


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の「ヘルパー」は、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));
        }
    }


6


ModelState全体をクリアすることもトリックを実行する場合があります。

ViewData.ModelState.Clear();


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


0


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

ModelState.Remove("ValueA");