Domanda

Questo comportamento mi sta facendo chiedo per la mia sanità mentale ..

Ho una forma che ha due posti che accettano input, chiamiamoli valoreA e valoreB. L'utente può immettere un valore in uno dei due e la forma sottomette.

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

L'azione di controllo è simile al seguente:

public ActionResult MyControllerAction(MyViewModel viewModel)
{

// fare altre cose ...

 return PartialView("MyPartialView", viewModel);
}

Il ViewModel è semplicemente questo:

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

Ora, il pezzo inaspettato. Dire la pagina inizialmente carichi e ValueB ha un valore di 7. L'utente cambia ValueA a 5 e la forma sottomette. Posso mettere un punto di interruzione nell'azione di controllo e vedere entrambi i valori nel parametro ViewModel. A questo punto, ValueA è 5 e ValueB è 0 (dovuto all'impostazione di ValueA). L'azione restituisce la ViewModel come parte del PartialView. Indietro nel parziale, posso mettere un punto di interruzione sulla Html.TextBox ( "ValueB", Model.ValueB, ...) la linea e vedere che è davvero ValueB 0. Ma quando la forma rende al browser, ValueB ha ancora un il valore di 7. E questo è dove mi sono bloccato. Ho anche cambiato il bersaglio Update per un div diverso, in modo che il parziale appena sputa il modulo in un posto completamente diverso, ma ha ancora il valore originale di 7, anche se ho visto attraverso il debug che il valore è stato 0 tornando dalla controller.

C'è qualcosa che mi manca?

È stato utile?

Soluzione

Ecco il codice dalla Fonte MVC per la casella di testo:

     string attemptedValue = (string)htmlHelper.GetModelStateValue(name, typeof(string));
                tagBuilder.MergeAttribute("value", attemptedValue ?? ((useViewData) ? htmlHelper.EvalString(name) : valueParameter**), isExplicitValue);
                break;

ed il codice per 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;
    }

Quindi, ciò che accade è l'Html "Helper" cerca il valore di casella di testo, facendo corrispondere il nome, nella tua ViewData.ModalState, se nel dizionario ModelState, è completamente ignora il valore fornito.

Quindi, tutto ciò che, se (valore> 0) {ValueA = 0; } Non importa, perché la sua intenzione di utilizzare i valori iscritti in ModelState se i nomi corrispondono.

Il modo in cui ho riparato questo è quello di soffiare via la ModalState prima che la vista rende per certi valori che voglio pasticciare con i miei modelli di vista. Questo è un codice che ho usato:

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

Altri suggerimenti

Cancellare l'intera ModelState potrebbe anche fare il trucco:

ViewData.ModelState.Clear();

grazie jfar .. questo è il codice 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

Come @jfar menzionato, rimuovendo la variabile dal ModelState nel controller farà il trucco. È possibile farlo con meno codice, anche se (in questi giorni, almeno).

ModelState.Remove("ValueA");
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top