Pergunta

Este comportamento está me fazendo perguntar sobre a minha sanidade mental ..

Eu tenho um formulário que tem dois lugares que aceitam entrada, vamos chamá-los de valorA e valorB. O usuário pode inserir um valor em qualquer um e os submete o formulário.

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

a ação do controlador se parece com isso:

public ActionResult MyControllerAction(MyViewModel viewModel)
{

// fazer algumas outras coisas ...

 return PartialView("MyPartialView", viewModel);
}

O ViewModel é simplesmente esta:

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

Agora, a peça inesperado. Dizem que a página inicialmente cargas e valorB tem um valor de 7. O usuário muda valorA a 5 e os submete o formulário. Eu posso colocar um ponto de interrupção na ação do controlador e ver ambos os valores no parâmetro viewmodel. Neste ponto, é valueA 5 e valorB é 0 (devido à definição de valueA). A ação retorna o ViewModel como parte do PartialView. Back in the parcial, posso colocar um ponto de interrupção na Html.TextBox ( "valorB", Model.ValueB, ...) de linha e ver que valorB é realmente 0. Mas quando o formulário torna para o navegador, valorB ainda tem um valor de 7. E isso é onde eu estou preso. Eu até mudaram o alvo Atualização de uma div diferente, de modo que as justas espetos lateral para a algum lugar forma completamente diferente, mas ainda tem o valor original de 7, mesmo que eu vi através de depuração que o valor é 0 voltando do controlador.

Existe algo que eu estou ausente?

Foi útil?

Solução

Aqui está o código da Fonte MVC para a caixa de texto:

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

E o código para 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;
    }

Então, o que acontece é que o HTML "Helper" olha para o valor da caixa de texto, combinando o nome, em sua ViewData.ModalState, se o seu no dicionário ModelState, ele ignora completamente o valor que fornecido.

Assim, tudo o que se (valor> 0) {valorA = 0; } Não importa, porque a sua vai usar os valores lançados no ModelState se os nomes correspondem.

A maneira que eu fixo isso é para soprar a ModalState antes da vista torna para certos valores que eu quero mexer com em meus modelos de exibição. Isto é algum código que eu usei:

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

Outras dicas

Limpeza de todo o ModelState também pode fazer o truque:

ViewData.ModelState.Clear();

graças jfar .. este é o código 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

Como @jfar mencionado, removendo a variável do ModelState em seu controlador irá fazer o truque. Você pode fazer isso com menos código, embora (nos dias de hoje, pelo menos).

ModelState.Remove("ValueA");
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top