2010-04-05 13 views
6

Das funktioniert, aber wie ???Wie erinnert sich asp.net MVC meine falschen Werte auf Postback?

Ich habe eine Controller-Aktion für einen Beitrag:

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Edit(Person person) 
{ 
    bool isvalid = ModelState.IsValid; 
    etc. 

Die Person-Objekt verfügt über eine Eigenschaft Geburtsdatum, Typ Datetime. Wenn ich einige ungültige Daten in das Formular eingeben, sage 'blabla', die offensichtlich kein gültiges Datetime ist, füllt es alle (andere) Person-Eigenschaften mit den richtigen Daten und die BirthDate-Eigenschaft mit einer neuen leeren DateTime. Das Bool isvalid hat den Wert 'false'. So weit so gut.

Dann mache ich das:

return View(p); 

und in der Ansicht, ich habe dies:

<%= Html.TextBox("BirthDate", String.Format("{0:g}", Model.BirthDate)) %> 
<%= Html.ValidationMessage("BirthDate", "*") %> 

Ant dort kommt es: i das Modell erwartet, dass die neue, leere Datetime enthalten, weil ich didn Wenn die Ansicht etwas anzeigt, muss es eine DateTime sein, da Model.BirthDate nur eine DateTime enthalten kann. Aber zu meiner Überraschung zeigt es eine Textbox mit dem 'blabla' Wert! (und das rote * dahinter)

Was natürlich ist schön, weil der Benutzer sehen kann, was er falsch eingegeben hat, aber wie kann diese (blabla) Zeichenkette in das Feld Ansicht in einem DateTime übertragen werden?

EDIT: Die ModelState Info hat mir hier sehr geholfen. Ich merke auch, dass in MVC 2, wenn Sie Ihre eigene Vorlage für Html.EditorFor() erstellen müssen Sie dieses Verhalten selbst implementieren. Ich habe ein

DateTime.ascx 

in dem/views/shared/EditorTemplates Ordner, und dort musste ich prüfen, ob ein Model Fehler für diese Eigenschaft Wert war, und wenn dies der Fall ist, zeige die ungültigen Daten anstelle von die Modelldaten.

So in der Ansicht Ich benutze diese:

<%= Html.LabelFor(model => model.DateOfBirth) %> 

und im DateTime.ascx ich benutze diese:

<% 
bool invalidData = false; 
string propertyName = ViewData.ModelMetadata.PropertyName; 

ModelState ms = ViewData.ModelState[propertyName]; 
if (ms != null) 
{ 
    invalidData = ms.Errors.Count > 0; 
} 
string valueToshow = invalidData ? ViewData.ModelState[propertyName].Value.AttemptedValue : String.Format("{0:g}", Model); 
%> 
<input class="text-box single-line" id="<%= propertyName %>" name="<%= propertyName %>" type="text" value="<%= valueToshow %>" /> 

Antwort

10

Model halten KeyValuePairs für jedes Formularelement mit dem Schlüssel der Feldname sein und der Wert ist, was du in das Feld legst. Dann suchen die Html-Helfer in ModelState und wenn Sie keinen Wert explizit angeben, ziehen sie den Wert von ModelState.

+0

Danke, haben jetzt nicht die Helfer mehr getan, als den Wert im Modell zu analysieren. – Michel

4

Der zuvor eingegebene Wert wird im ModelState gespeichert. Wenn Sie einen Fehler im Formular haben, zieht der Helfer den Wert aus dem ModelState, anstatt entweder Werte aus dem Modell oder die speziell gelieferten zu verwenden (unter der Haube, wenn Sie keinen expliziten Wert angeben, wird das Modell als Standard verwendet) Wert, wenn es einen gibt, wenn keine Fehler vorliegen).

+0

+1 für die Antwort, Keith war etwas schneller, hoffe, es macht Ihnen nichts aus, seine Antwort zu markieren – Michel

+0

Ich denke, diese Antwort ist richtig, und Keith ist nicht genau richtig. Keiths Antwort besagt, dass ModelState verwendet wird, wenn Sie keinen Wert explizit angeben; Diese Antwort besagt, dass ModelState bei einem Fehler verwendet wird, unabhängig davon, ob ein Wert explizit angegeben wurde oder nicht. Das Muster zum Aufrufen des GET-Controllers nach dem POST-Controller bei einem Modellfehler funktioniert nur, weil die View-Daten von ModelState immer alles überschreiben, was Sie im GET-Controller codieren. –

1

Ich hatte etwas Code in der "Postback", die ungültige Promo-Codes entfernen und die Antwort groß schreiben würde. Auch wenn Sie das Modell mit dem neuen Wert aktualisieren, wird es nicht angezeigt, da der ModelState-Wert Vorrang hat (wie andere bereits beantwortet haben).

<%= Html.TextBox("PromoCode", Model.PromoCodes) %> 

Aber wenn man einen Fall, in dem dies geschah, und Sie wollen nicht der alte Wert beibehalten Sie dies tun müssen:

ModelState.Remove("PromoCode"); 

oder setzen explizit den neuen Wert in Model (wahrscheinlich der bessere Ansatz):

ModelState.SetModelValue("PromoCode", 
     new ValueProviderResult(newValue, newValue, CultureInfo.CurrentCulture)); 
+0

+1 für die Addition. – Michel

Verwandte Themen