Używam MVC 3 w moim projekcie i widzę bardzo dziwne zachowanie.
Próbuję utworzyć ukryte pole dla określonej wartości w moim modelu, problem polega na tym, że z jakiegoś powodu wartość ustawiona w polu nie odpowiada wartości w modelu.
na przykład
Mam taki kod jako test:
<%:Html.Hidden("Step2", Model.Step) %>
<%:Html.HiddenFor(m => m.Step) %>
Myślę, że oba ukryte pola miałyby taką samą wartość. Robię to, ustawiając wartość na 1, gdy po raz pierwszy wyświetlam Widok, a następnie po przesłaniu zwiększam wartość pola Model o 1.
Tak więc przy pierwszym renderowaniu strony obie kontrolki mają wartość 1, ale przy drugim renderowaniu wartości są następujące:
<input id="Step2" name="Step2" type="hidden" value="2" />
<input id="Step" name="Step" type="hidden" value="1" />
Jak widać, pierwsza wartość jest poprawna, ale druga wartość wydaje się być taka sama, jak przy pierwszym wyświetleniu widoku.
czego mi brakuje? Czy pomocnicy * For Html buforują wartości w jakiś sposób? Jeśli tak, jak mogę wyłączyć to buforowanie ?.
Dzięki za pomoc.
Odpowiedzi:
To normalne i tak działają pomocnicy HTML. Najpierw używają wartości żądania POST, a następnie wartości w modelu. Oznacza to, że nawet jeśli zmodyfikujesz wartość modelu w akcji kontrolera, jeśli w żądaniu POST znajduje się ta sama zmienna, modyfikacja zostanie zignorowana i zostanie użyta wartość POST.
Jednym z możliwych obejść jest usunięcie tej wartości ze stanu modelu w akcji kontrolera, która próbuje zmodyfikować wartość:
// remove the Step variable from the model state // if you want the changes in the model to be // taken into account ModelState.Remove("Step"); model.Step = 2;
Inną możliwością jest napisanie niestandardowego pomocnika HTML, który zawsze będzie używał wartości modelu i ignorował wartości POST.
I jeszcze jedna możliwość:
<input type="hidden" name="Step" value="<%: Model.Step %>" />
źródło
Napotkałem ten sam problem podczas pisania kreatora, który na każdym kroku pokazuje różne części większego modelu.
Dane i / lub błędy z „kroku 1” pomieszałyby się z „krokiem 2”, itd., Aż w końcu zdałem sobie sprawę, że „winę” ponosi ModelState.
To było moje proste rozwiązanie:
if (oldPageIndex != newPageIndex) { ModelState.Clear(); // <-- solution } return View(model[newPageIndex]);
źródło
ModelState.Clear()
rozwiązałem mój problem z kolejnymi żądaniami POST w podobnej sytuacji.Ten kod nie będzie działał
// remove the Step variable from the model state // if you want the changes in the model to be // taken into account ModelState.Remove("Step"); model.Step = 2;
... ponieważ HiddenFor zawsze (!) czyta z ModelState, a nie sam model. A jeśli nie znajdzie klucza „Step”, wygeneruje wartość domyślną dla tego typu zmiennej, która w tym przypadku będzie wynosić 0
Oto rozwiązanie. Napisałem to dla siebie, ale nie mam nic przeciwko udostępnieniu, ponieważ widzę, że wiele osób zmaga się z tym niegrzecznym pomocnikiem HiddenFor.
public static class CustomExtensions { public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) { ReplacePropertyState(htmlHelper, expression); return htmlHelper.HiddenFor(expression); } public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes) { ReplacePropertyState(htmlHelper, expression); return htmlHelper.HiddenFor(expression, htmlAttributes); } public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes) { ReplacePropertyState(htmlHelper, expression); return htmlHelper.HiddenFor(expression, htmlAttributes); } private static void ReplacePropertyState<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) { string text = ExpressionHelper.GetExpressionText(expression); string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(text); ModelStateDictionary modelState = htmlHelper.ViewContext.ViewData.ModelState; ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); if (modelState.ContainsKey(fullName)) { ValueProviderResult currentValue = modelState[fullName].Value; modelState[fullName].Value = new ValueProviderResult(metadata.Model, Convert.ToString(metadata.Model), currentValue.Culture); } else { modelState[fullName] = new ModelState { Value = new ValueProviderResult(metadata.Model, Convert.ToString(metadata.Model), CultureInfo.CurrentUICulture) }; } } }
Następnie po prostu używaj go jak zwykle z poziomu widoku:
Warto wspomnieć, że działa również z kolekcjami.
źródło
Myślę, że zbyt zmagam się z taką samą sytuacją, w której używam tego samego stanu modelu między wywołaniami i kiedy zmieniam właściwość modelu na zapleczu. Chociaż nie ma dla mnie znaczenia, czy używam textboxfor, czy hiddenfor.
Po prostu omijam tę sytuację, używając skryptów strony do przechowywania wartości modelu jako zmiennej js, ponieważ na początku potrzebuję do tego celu hiddenfield.
Nie jestem pewien, czy to pomoże, ale zastanów się ...
źródło