2010-04-05 3 views
6

Cela fonctionne, mais comment ???Comment asp.net MVC se souvient-il de mes valeurs incorrectes à la publication?

J'ai une action de contrôleur pour un poste:

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

L'objet personne a une date de naissance de la propriété, le type DateTime. Lorsque j'entre une donnée invalide dans le formulaire, disons 'blabla' qui n'est pas une Datetime valide, elle remplit toutes les propriétés (other) Person avec les données correctes et la propriété BirthDate avec un nouveau DateTime vide. Le bool isvalid a la valeur 'false'. Jusqu'ici tout va bien.

Puis-je faire ceci:

return View(p); 

et dans la vue j'ai ceci:

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

Ant là, il vient: I expected le modèle pour contenir le nouveau DateTime blanc parce que je didn Ne mettez pas de nouvelles données. Deuxièmement, lorsque la vue affiche quelque chose, elle doit être un DateTime, car Model.BirthDate ne peut pas contenir autre chose qu'un DateTime. Mais à ma grande surprise, il affiche une zone de texte avec la valeur 'blabla'! (et le rouge * derrière)

Ce qui est bien sûr parce que l'utilisateur peut voir ce qu'il a mal tapé, mais comment cette chaîne (blabla) peut-elle être transférée au champ View dans un champ DateTime?

EDIT: L'information ModelState m'a beaucoup aidé ici. Je remarque également que dans MVC 2, lorsque vous créez votre propre modèle pour Html.EditorFor() vous devez implémenter ce comportement vous-même. J'ai créé un

DateTime.ascx 

dans le répertoire/vues/partagé/dossier EditorTemplates, et là, je devais vérifier s'il y avait une erreur de ModelState pour cette valeur de la propriété, et le cas échéant, afficher les données invalides au lieu de les données du modèle.

Ainsi, dans la vue j'utiliser ceci:

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

et dans le DateTime.ascx j'utilise ceci:

<% 
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 %>" /> 

Répondre

10

ModelState détient KeyValuePairs pour chaque élément de forme avec la clé étant le nom du champ et la valeur est ce que vous mettez sur le terrain. Les assistants Html regardent alors dans ModelState et si vous ne spécifiez pas explicitement une valeur, ils tireront la valeur de ModelState.

+0

Merci, n'a pas maintenant les assistants ont fait plus alors l'analyse de la valeur dans le modèle. – Michel

4

La valeur entrée précédemment est stockée dans ModelState. Lorsque vous avez une erreur sur le formulaire, l'assistant extrait la valeur de ModelState au lieu d'utiliser les valeurs du modèle ou celles fournies spécifiquement (sous le capot, si vous ne fournissez pas de valeur explicite, le modèle sera défini par défaut sur le modèle). valeur s'il y en a une s'il n'y a pas d'erreurs).

+0

+1 pour la réponse, Keith était légèrement plus rapide, j'espère que cela ne vous dérange pas de marquer son comme réponse – Michel

+0

Je pense que cette réponse est correcte, et Keith n'est pas tout à fait raison. La réponse de Keith indique que ModelState est utilisé si vous ne spécifiez pas explicitement une valeur; cette réponse indique que ModelState est utilisé s'il y a une erreur, qu'une valeur ait été explicitement spécifiée ou non. Le motif pour appeler le contrôleur GET après le contrôleur POST en cas d'erreur de modèle ne fonctionne que parce que les données de vue ModelState remplacent toujours tout ce que vous codez dans le contrôleur GET. –

1

J'avais du code dans le 'postback' qui supprimait les codes promotionnels invalides et mettait la majuscule à zéro. Même si vous mettez à jour le modèle avec la nouvelle valeur, il ne sera pas affiché car la valeur ModelState a la priorité (comme d'autres ont déjà répondu).

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

Mais si vous avez un cas où cela se passait et vous ne voulez pas l'ancienne valeur que vous avez persisté devez faire ceci:

ModelState.Remove("PromoCode"); 

ou définir explicitement la nouvelle valeur dans ModelState (probablement la meilleure approche):

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

+1 pour l'addition. – Michel

Questions connexes