2010-05-12 9 views
1

J'ai quelques problèmes avec le classeur modèle par défaut d'ASP.NET MVC. La vue contient HTML comme ceci:asp.net mvc problème de liaison de modèle par défaut

<input name="SubDTO[0].Id" value="1" type="checkbox"> 
<input name="SubDTO[1].Id" value="2" type="checkbox"> 

Ceci est mon simplifié 'modèle':

public class SubDTO 
{ 
    public virtual string Id { get; set; } 
} 

public class DTO 
{ 
    public List<SubDTO> SubDTOs { get; set; } 

    public DTO() 
{ 
    SubDTOs = new List< SubDTO>(); 
} 
} 

Tout cela fonctionne très bien si l'utilisateur sélectionne au moins la première case à cocher (SubDTO [0] .id) . Le contrôleur "reçoit" un DTO bien initialisé/lié. Toutefois, si la première case à cocher n'est pas sélectionnée mais uniquement, par exemple, SubDTO [1] .Id l'objet SubDTOs est null. Quelqu'un peut-il expliquer ce comportement «étrange» et comment le surmonter? Merci.

Meilleurs voeux,

Christian

PS:

Le contrôleur ressemble à ceci:

 [Transaction] 
     [AcceptVerbs(HttpVerbs.Post)] 
     public RedirectToRouteResult Create(DTO DTO) 
     { 
... 
} 

PPS:

Mon problème est que si je sélectionne la case SubDTO [0] .Id, SubDTO [1] .Id, SubDTO [2] .Id SubDTOs est initialisé. Mais si je sélectionne simplement la case à cocher SubDTO [1] .Id, SubDTO [2] .Id (PAS la première !!!) SubDTO reste null. J'ai inspecté les valeurs affichées (en utilisant firebug) et ils sont postés !!! Cela doit être un bogue dans le classeur par défaut ou peut-être manquer quelque chose.

+0

Pouvez-vous également publier votre code d'action? – Lazarus

+0

ok done - voir ps. merci – cs0815

+0

Le classeur de modèle va essayer un nom de valeur de correspondance dans vos valeurs de retour aux noms de propriété dans votre objet. – Lazarus

Répondre

2

Ce comportement est "par conception" en html. Si une case est cochée, sa valeur est envoyée au serveur. Si elle n'est pas cochée, rien n'est envoyé. C'est pourquoi vous obtenez null dans votre action et vous ne trouverez pas non plus de valeur dans le formulaire affiché. La façon de contourner est d'ajouter un champ caché avec le même nom et une valeur après la case comme ceci:

<input name="SubDTO[0].Id" value="true" type="checkbox"> 
<input name="SubDTO[0].Id" value="false" type="hidden"> 
<input name="SubDTO[1].Id" value="true" type="checkbox">  
<input name="SubDTO[1].Id" value="false" type="hidden"> 

De cette façon, si vous cochez la case les deux valeurs seront envoyées, mais la modèle liant prendra seulement le premier. Si la case à cocher n'est pas cochée, seule la valeur du champ caché sera envoyée et vous l'obtiendrez dans l'action au lieu de la valeur null.

+0

Mon problème est que si je sélectionne checkbox SubDTO [0] .Id, SubDTO [1] .Id, SubDTO [2] .Id choses sont initialisées. Mais si je sélectionne simplement la case à cocher SubDTO [1] .Id, SubDTO [2] .Id (PAS la première !!!) SubDTO reste null. J'ai inspecté les valeurs affichées (en utilisant firebug) et ils sont postés !!! Par conséquent, cela ne peut pas être «par conception» mais doit être un bogue dans le classeur par défaut. – cs0815

+0

Vous semblez avoir édité votre réponse, donc je l'ai accepté. Merci! – cs0815

1

Modifier le balisage comme suit:

<input name="SubDTOs" value="<%= SubDTO[0].Id %>" type="checkbox"> 
<input name="SubDTOs" value="<%= SubDTO[1].Id %>" type="checkbox"> 

Ce qui est retourné par votre balisage d'origine est un ensemble sans rapport avec des paramètres, à savoir comme appeler RedirectToRouteResult Create(SubDTO[0].id, SubDTO[1].id, ..., SubDTO[n].id) qui est clairement pas ce que vous voulez, vous voulez un tableau retourné dans votre Objet DTO donc en donnant à toutes les cases à cocher le même nom la valeur de retour à votre fonction sera un tableau d'identifiants.

EDIT

Essayez ceci:

<input name="SubDTO[0].Id" value="<%= SubDTO[0].Id %>" type="checkbox"> 
<input name="SubDTO[0].Id" value="false" type="hidden"> 
<input name="SubDTO[1].Id" value="<%= SubDTO[1].Id %>" type="checkbox"> 
<input name="SubDTO[1].Id" value="false" type="hidden"> 

Vous devez retourner quelque chose à vous assurer qu'il ya un élément pour chaque indice, je soupçonne que tout écart causera un problème si je Suggérons d'utiliser un identifiant 'null', par exemple 0 ou -1, puis le traiter plus tard dans votre code. Une autre réponse serait un classeur modèle personnalisé.

Il existe toujours l'option alternative d'ajouter une propriété à votre classe qui prend un tableau de chaînes et crée le tableau SubDTO à partir de cela.

public List<string> SubDTOIds 
{ 
    get { return SubDTO.Select(s=>s.Id).ToList(); } 
    set 
    { 
     SubDTOs = new List< SubDTO>(); 
     foreach (string id in value) 
     { 
      SubDTOs.Add(new SubDTO { Id = id }); 
     } 
    } 
} 

ou quelque chose comme ça

+0

je pouvais avoir: Liste SubDTOs dans mon DTO et utilisation: pas de problème! Mais j'ai besoin du chemin d'accès: SubDTO.Id si vous voyez ce que je veux dire. S'il vous plaît noter que la valeur est une clé pimary réelle (dynamique) et mes cases à cocher sont générés via un helper html. – cs0815

+0

Non, je ne sais pas ce que tu veux dire. Vous utilisez la chaîne littérale "SubDTO [0] .Id" comme nom pour une case à cocher où ce que je pense que vous voulez est comme ci-dessus, la case à cocher pour retourner la * valeur * de SubDTO [0] .Id ". En utilisant le code ci-dessus, vous obtiendrez un tableau des ID SubDTO "vérifiés" transmis au classeur du modèle – Lazarus

+0

L'idée est que SubDTO [0].Id affecterait la valeur de la case à cocher à l'Id du premier objet dans les sous-objets (List ). Cela semble fonctionner correctement tant que je publie au moins le nom SubDTO [0] .Id et sa valeur! – cs0815

1

Je pense que this après sur le blog de Scott Hanselman vous expliquera pourquoi. La ligne est pertinente:

The index must be zero-based and unbroken. In the above example, because there was no people[2], we stop after Abraham Lincoln and don’t continue to Thomas Jefferson.

Ainsi, dans votre cas parce que le premier élément est pas retourné (comme expliqué par d'autres comme le comportement par défaut pour les cases à cocher) la collection ne sont pas en cours d'initialisation.

+0

Merci d'avoir vérifié mon hypothèse! +1 – Lazarus

+0

Merci Lester cela explique je suppose. Existe-t-il une alternative à mes cases à cocher pour réaliser le comportement ci-dessus? Merci! – cs0815

Questions connexes