Если значение изменяется в модели после публикации, форма по-прежнему отображает старое значение - PullRequest
7 голосов
/ 04 декабря 2009

Такое поведение заставляет меня задуматься о моем здравомыслии ..

У меня есть форма, в которой есть два места для ввода данных, назовем их 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). Действие возвращает viewModel как часть PartialView. Вернувшись в частичное, я могу поставить точку останова в строке Html.TextBox («ValueB», Model.ValueB, ...) и увидеть, что ValueB действительно равен 0. Но когда форма отображается в браузере, ValueB по-прежнему имеет значение 7. И вот где я застрял. Я даже изменил цель обновления на другой div, так что частичное просто выплевывает форму где-то совершенно иначе, но оно по-прежнему имеет первоначальное значение 7, хотя в процессе отладки я видел, что значение 0 возвращалось из контроллер.

Что-то мне не хватает?

Ответы [ 4 ]

7 голосов
/ 04 декабря 2009

Вот код из источника 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, оно полностью игнорирует указанное вами значение .

Так что все, что если (значение> 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 голосов
/ 09 ноября 2010

Очистка всего ModelState также может помочь:

ViewData.ModelState.Clear();
0 голосов
/ 13 июня 2013

Как уже упоминалось @jfar, удаление переменной из ModelState в вашем контроллере поможет. Вы можете сделать это с меньшим количеством кода, хотя (в наши дни, по крайней мере).

ModelState.Remove("ValueA");
0 голосов
/ 18 июля 2010

спасибо 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...