ASP.NET MVC 3 - Partiel vs modèle d'affichage vs modèle d'éditeur

303

Ainsi, le titre devrait parler de lui-même.

Pour créer des composants réutilisables dans ASP.NET MVC, nous avons 3 options (pourraient être d'autres que je n'ai pas mentionnées):

Vue partielle:

@Html.Partial(Model.Foo, "SomePartial")

Modèle d'éditeur personnalisé:

@Html.EditorFor(model => model.Foo)

Modèle d'affichage personnalisé:

@Html.DisplayFor(model => model.Foo)

En termes de View / HTML, les trois implémentations sont identiques:

@model WebApplications.Models.FooObject

<!-- Bunch of HTML -->

Donc, ma question est - quand / comment décidez-vous lequel des trois utiliser?

Ce que je recherche vraiment, c'est une liste de questions à vous poser avant d'en créer une, pour laquelle les réponses peuvent être utilisées pour décider du modèle à utiliser.

Voici les 2 choses que j'ai mieux trouvées avec EditorFor / DisplayFor:

  1. Ils respectent les hiérarchies de modèles lors du rendu des assistants HTML (par exemple, si vous avez un objet "Bar" sur votre modèle "Foo", les éléments HTML de "Bar" seront rendus avec "Foo.Bar.ElementName", tandis qu'un partiel aura " ElementName ").

  2. Plus robuste, par exemple, si vous aviez List<T>quelque chose dans votre ViewModel, vous pourriez l'utiliser @Html.DisplayFor(model => model.CollectionOfFoo), et MVC est assez intelligent pour voir qu'il s'agit d'une collection et afficher l'affichage unique pour chaque élément (par opposition à un partiel, qui nécessiterait une explicite pour boucle).

J'ai également entendu que DisplayFor rend un modèle "en lecture seule", mais je ne le comprends pas - ne pourrais-je pas y envoyer un formulaire?

Quelqu'un peut-il me dire d'autres raisons? Existe-t-il quelque part une liste / un article comparant les trois?

RPM1984
la source
Les concepts derrière l'éditeur et les modèles d'affichage sont clairement définis dans la documentation d'asp.net mvc 2. Les modèles sont des partiels qui adhèrent à une convention spécifique. Les situations qui rendent les modèles meilleurs ou pires que les anciens partiels dépendent presque strictement du respect ou non de la convention dans votre application.
Nick Larsen

Réponses:

301

EditorForvs DisplayForest simple. La sémantique des méthodes est de générer des vues d'édition / insertion et d'affichage / lecture seule (respectivement). À utiliser DisplayForlors de l'affichage de données (c'est-à-dire lorsque vous générez des divs et des étendues contenant les valeurs du modèle). À utiliser EditorForlors de la modification / insertion de données (c'est-à-dire lorsque vous générez des balises d'entrée dans un formulaire).

Les méthodes ci-dessus sont centrées sur le modèle. Cela signifie qu'ils prendront en compte les métadonnées du modèle (par exemple, vous pourriez annoter votre classe de modèle avec [UIHintAttribute]ou [DisplayAttribute]et cela influencerait le modèle choisi pour générer l'interface utilisateur du modèle. Ils sont également généralement utilisés pour les modèles de données (c'est-à-dire les modèles qui représenter des lignes dans une base de données, etc.)

D'un autre côté, la Partialvue est centrée sur le fait que vous vous souciez principalement de choisir la vue partielle correcte. La vue n'a pas nécessairement besoin d'un modèle pour fonctionner correctement. Il peut simplement avoir un ensemble de balisage commun qui est réutilisé dans tout le site. Bien sûr, il arrive souvent que vous souhaitiez affecter le comportement de ce partiel, auquel cas vous souhaiterez peut-être passer dans un modèle de vue approprié.

Vous n'avez pas demandé @Html.Actionce qui mérite également d'être mentionné ici. Vous pouvez le considérer comme une version plus puissante de Partialdans la mesure où il exécute une action enfant du contrôleur, puis rend une vue (qui est généralement une vue partielle). Ceci est important car l'action enfant peut exécuter une logique métier supplémentaire qui n'appartient pas à une vue partielle. Par exemple, il pourrait représenter un composant de panier d'achat. La raison de l'utiliser est d'éviter d'effectuer le travail lié au panier dans chaque contrôleur de votre application.

En fin de compte, le choix dépend de ce que vous modélisez dans votre application. N'oubliez pas que vous pouvez mélanger et assortir. Par exemple, vous pouvez avoir une vue partielle qui appelle l' EditorForassistant. Cela dépend vraiment de ce qu'est votre application et de la façon de la prendre en compte pour encourager une réutilisation maximale du code tout en évitant la répétition.

marcind
la source
4
C'est une excellente réponse, exactement ce que je cherchais. En réalité, je comptais sur le fait que vous veniez répondre à cette question. :) Merci marcin.
RPM1984
Comment utilisez-vous des annotations pour spécifier un modèle d'affichage et un modèle d'éditeur pour une seule propriété?
stormwild
3
@stormwild utilise la convention et nomme vos modèles d'après le modèle auquel ils se rapportent (/Views/DisplayTemplates/MyModel.cshtml) ou le force explicitement avec l'annotation UIHint.
Tom Wayson
Un conseil à choisir pour créer un assistant réutilisable "enregistrer l'utilisateur"? Je veux créer ces vues (et contrôleurs) dans un assemblage séparé si possible. Aka, un moyen de redistribuer entre plusieurs équipes ces formulaires / contrôleurs mvc réutilisables. (nous avons créé une façon unique de gérer les utilisateurs / le stockage (services webapi) ... mais chaque équipe crée ses propres pages mvc: <Merci.
granadaCoder
Où stockez-vous ces modèles? Dois-je les stocker dans Shared / EditorTemplates ou est-il possible de les stocker directement dans le dossier du contrôleur actuel (lorsque je n'en ai besoin que là-bas)?
Santhos
15

Vous certainement pouvez personnaliser DisplayForpour afficher une forme modifiable. Mais la convention est DisplayFord'être readonlyet EditorFord'être pour le montage. S'en tenir à la convention garantira que peu importe dans quoi vous passerez DisplayFor, cela fera le même genre de chose.

Robert Levy
la source
2
Je ne pense pas qu'il y ait vraiment de question / doute quant à savoir quand utiliser des modèles d'affichage contre des modèles d'éditeur. La vraie question semble être de savoir quand utiliser des modèles par rapport aux partiels. Votre réponse manque complètement cela.
Joshua Hayes
19
@Joshua - je pense qu'il y avait une question à cela: "J'ai également entendu que DisplayFor rend un modèle" en lecture seule ", mais je ne comprends pas - ne pourrais-je pas y envoyer un formulaire?"
Robert Levy
13

Juste pour donner ma valeur à 2c, notre projet utilise une vue partielle avec plusieurs onglets jQuery, et chaque onglet rend ses champs avec sa propre vue partielle. Cela a bien fonctionné jusqu'à ce que nous ajoutions une fonctionnalité permettant à certains onglets de partager certains champs communs. Notre première approche a consisté à créer une autre vue partielle avec ces champs communs, mais cela est devenu très maladroit lorsque vous utilisez EditorFor et DropDownListFor pour rendre les champs et les listes déroulantes. Afin d'obtenir des identifiants et des noms uniques, nous avons dû rendre les champs avec un préfixe en fonction de la vue partielle parent qui le rendait:

    <div id="div-@(idPrefix)2" class="toHide-@(idPrefix)" style="display:none">
    <fieldset>
        <label for="@(idPrefix).Frequency">Frequency<span style="color: #660000;"> *</span></label>

        <input name="@(idPrefix).Frequency"
               id="@(idPrefix)_Frequency"
               style="width: 50%;"
               type="text"
               value="@(defaultTimePoint.Frequency)"
               data-bind="value: viewState.@(viewStatePrefix).RecurringTimepoints.Frequency"
               data-val="true"
               data-val-required="The Frequency field is required."
               data-val-number="The field Frequency must be a number."
               data-val-range-min="1"
               data-val-range-max="24"
               data-val-range="The field Frequency must be between 1 and 24."
               data-val-ignore="true"/>

        @Html.ValidationMessage(idPrefix + ".Frequency")

        ... etc

    </fieldset>
</div>

Cela est devenu assez laid, nous avons donc décidé d'utiliser des modèles d'édition à la place, ce qui a fonctionné beaucoup plus propre. Nous avons ajouté un nouveau modèle de vue avec les champs communs, ajouté un modèle d'éditeur correspondant et rendu les champs à l'aide du modèle d'éditeur à partir de différentes vues parent. Le modèle de l'éditeur affiche correctement les identifiants et les noms.

Donc, en bref, une raison convaincante pour nous d'utiliser des modèles d'éditeur était la nécessité de rendre certains champs communs dans plusieurs onglets. Les vues partielles ne sont pas conçues pour cela, mais les modèles de l'éditeur gèrent parfaitement le scénario.

Ciaran Bruen
la source
1
J'ai eu un problème similaire en utilisant des onglets et j'ai fini par utiliser BeginCollectionItem de Steve Sanderson qui génère les identifiants de contrôle uniques pour vous: blog.stevensanderson.com/2010/01/28/…
Wilky
1

Utilisez l' _partialapproche de la vue si:

  1. Voir Centric Logic
  2. De quoi conserver tous _partialles HTML liés à la vue dans cette vue uniquement. Dans la méthode du modèle, vous devrez conserver du code HTML en dehors de la vue du modèle, comme "En-tête principal ou toute bordure / paramètres externes.
  3. Vous voulez rendre une vue partielle avec la logique (depuis le contrôleur) à l'aide de URL.Action("action","controller").

Raisons d'utiliser le modèle:

  1. Vous souhaitez supprimer ForEach(Iterator). Le modèle suffit pour identifier le modèle comme type de liste. Il le fera automatiquement.
  2. Model Centric Logic. Si plusieurs vues se trouvent dans le même dossier displayfor Template, le rendu dépendra du modèle passé.
jitendra joshi
la source
1

Une autre différence qui n'a pas été mentionnée jusqu'à présent est qu'une vue partielle n'ajoute pas de préfixes de modèle alors qu'un modèle le fait Voici le problème

erhan355
la source