ASP.NET MVC 3 - Modelo de exibição parcial versus modelo de editor

303

Portanto, o título deve falar por si.

Para criar componentes reutilizáveis ​​no ASP.NET MVC, temos 3 opções (podem ser outras que eu não mencionei):

Vista parcial:

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

Modelo de editor personalizado:

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

Modelo de exibição personalizado:

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

Em termos da visualização / HTML real, todas as três implementações são idênticas:

@model WebApplications.Models.FooObject

<!-- Bunch of HTML -->

Então, minha pergunta é - quando / como você decide qual dos três usar?

O que realmente estou procurando é uma lista de perguntas a serem feitas antes de criar uma, para as quais as respostas podem ser usadas para decidir qual modelo usar.

Aqui estão as 2 coisas que eu achei melhor com o EditorFor / DisplayFor:

  1. Eles respeitam as hierarquias do modelo ao renderizar auxiliares de HTML (por exemplo, se você tiver um objeto "Bar" no modelo "Foo", os elementos HTML de "Bar" serão renderizados com "Foo.Bar.ElementName", enquanto um parcial terá " ElementName ").

  2. Mais robusto, por exemplo, se você tivesse List<T>algo em seu ViewModel, poderia usar @Html.DisplayFor(model => model.CollectionOfFoo), e o MVC é inteligente o suficiente para ver que é uma coleção e exibir a única exibição de cada item (em oposição a um Parcial, o que exigiria explícito para ciclo).

Eu também ouvi o DisplayFor renderizar um modelo "somente leitura", mas eu não entendo isso - eu não poderia lançar um formulário lá?

Alguém pode me dizer outras razões? Existe uma lista / artigo em algum lugar comparando os três?

RPM1984
fonte
Os conceitos por trás dos modelos de editor e exibição estão claramente definidos na documentação do asp.net mvc 2. Os modelos são parciais que aderem a uma convenção específica. As situações que tornam os modelos melhores ou piores que as parciais antigas dependem quase estritamente de se a convenção vale ou não a adesão ao seu aplicativo.
Nick Larsen

Respostas:

301

EditorForvs DisplayForé simples. A semântica dos métodos é gerar visualizações de edição / inserção e exibição / leitura somente (respectivamente). Use DisplayForao exibir dados (ou seja, ao gerar divs e spans que contêm os valores do modelo). Use EditorForao editar / inserir dados (ou seja, ao gerar tags de entrada dentro de um formulário).

Os métodos acima são centrados no modelo. Isso significa que eles levarão em consideração os metadados do modelo (por exemplo, você pode anotar sua classe de modelo [UIHintAttribute]ou [DisplayAttribute]influenciar qual modelo é escolhido para gerar a interface do usuário para o modelo. Eles também são geralmente usados ​​para modelos de dados (por exemplo, modelos que representar linhas em um banco de dados, etc)

Por outro lado, Partialé centrada na visualização, pois você se preocupa principalmente com a escolha da visualização parcial correta. A visualização não precisa necessariamente de um modelo para funcionar corretamente. Ele pode ter apenas um conjunto comum de marcação reutilizado em todo o site. É claro que muitas vezes você deseja afetar o comportamento dessa parcial; nesse caso, você pode querer passar em um modelo de vista apropriado.

Você não perguntou sobre o @Html.Actionque também merece uma menção aqui. Você pode pensar nisso como uma versão mais poderosa, Partialna medida em que executa uma ação filho do controlador e, em seguida, renderiza uma exibição (que geralmente é uma exibição parcial). Isso é importante porque a ação filho pode executar lógica de negócios adicional que não pertence a uma exibição parcial. Por exemplo, poderia representar um componente do carrinho de compras. O motivo para usá-lo é evitar executar o trabalho relacionado ao carrinho de compras em todos os controladores do seu aplicativo.

Por fim, a escolha depende do que você está modelando em seu aplicativo. Lembre-se também de que você pode misturar e combinar. Por exemplo, você pode ter uma visão parcial que chama o EditorForauxiliar. Realmente depende do que é seu aplicativo e como fatorá-lo para incentivar a reutilização máxima de código, evitando repetições.

marcind
fonte
4
Essa é uma ótima resposta, exatamente o que eu estava procurando. Na realidade, eu estava apostando no fato de que você viria e responderia a isso. :) Obrigado marcin.
RPM1984
Como você usa anotações para especificar um modelo de exibição e um modelo de editor para uma única propriedade?
stormwild
3
@stormwild use a convenção e nomeie seus modelos de acordo com o modelo ao qual eles se relacionam (/Views/DisplayTemplates/MyModel.cshtml) ou force-o explicitamente com a anotação UIHint.
Tom Wayson
Algum conselho para escolher para criar um assistente de "usuário de registro" reutilizável? Eu quero criar essas visualizações (e controladores) em um assembly separado, se possível. Aka, uma maneira de redistribuir entre várias equipes esses formulários / controladores de mvc que podem ser recuperados. (criamos uma única maneira de utilizador alça / armazenamento (serviços WebAPI) ... mas cada equipe está criando suas próprias páginas MVC: <Graças.
granadaCoder
Onde você armazena esses modelos? Preciso armazená-los no Shared / EditorTemplates ou é possível armazená-los diretamente na pasta atual do controlador (quando preciso deles apenas lá)?
Santhos
15

Você certamente pode personalizar DisplayForpara exibir um formulário editável. Mas a convenção é para DisplayForser readonlye EditorForser para edição. Manter a convenção garantirá que, não importa o que você passe DisplayFor, ele fará o mesmo tipo de coisa.

Robert Levy
fonte
2
Eu não acho que haja realmente alguma dúvida / dúvida sobre quando alguém deve usar modelos de exibição versus modelos de editor. A verdadeira questão parece ser quando você deve usar modelos versus parciais. Sua resposta perde completamente isso.
Joshua Hayes
19
@ Josué - acho que houve uma pergunta: "Eu também ouvi o DisplayFor renderizar um modelo" somente leitura ", mas eu não entendo isso - não poderia jogar um formulário lá?"
Robert Levy
13

Apenas para dar meu valor de 2c, nosso projeto está usando uma exibição parcial com várias guias do jQuery, e cada guia processando seus campos com sua própria vista parcial. Isso funcionou bem até que adicionamos um recurso no qual algumas das guias compartilhavam alguns campos comuns. Nossa primeira abordagem para isso foi criar outra exibição parcial com esses campos comuns, mas isso ficou muito complicado ao usar EditorFor e DropDownListFor para renderizar campos e menus suspensos. Para obter os IDs e nomes exclusivos, tivemos que renderizar os campos com um prefixo, dependendo da exibição parcial pai que estava renderizando:

    <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>

Como ficou muito feio, decidimos usar os Modelos de Editor, o que resultou muito mais limpo. Adicionamos um novo modelo de vista com os campos comuns, adicionamos um modelo de editor correspondente e renderizamos os campos usando o modelo de editor de diferentes visualizações pai. O modelo do editor renderiza corretamente os IDs e nomes.

Portanto, em resumo, um motivo convincente para usarmos os Modelos de Editor foi a necessidade de renderizar alguns campos comuns em várias guias. As vistas parciais não foram projetadas para isso, mas os Modelos de Editor lidam perfeitamente com o cenário.

Ciaran Bruen
fonte
1
Eu tive um problema semelhante usando guias e acabou usando BeginCollectionItem de Steve Sanderson, que gera o ID de controle único é para você: blog.stevensanderson.com/2010/01/28/...
Wilky
1

Use a _partialabordagem de exibição se:

  1. Exibir lógica central
  2. O que manter todo o _partialHTML relacionado à visualização apenas nesta visualização. No método de modelo, você precisará manter um pouco de HTML fora da Visualização de modelo, como "Cabeçalho principal ou qualquer borda / configuração externa.
  3. Deseja renderizar vista parcial com lógica (do controlador) usando URL.Action("action","controller").

Razões para usar o Template:

  1. Deseja remover ForEach(Iterator). O modelo é suficiente para identificar o modelo como um tipo de lista. Isso será feito automaticamente.
  2. Lógica centrada em modelo. Se várias visualizações forem encontradas na mesma exibição da pasta Modelo, a renderização dependerá do Modelo passado.
jitendra joshi
fonte
1

Outra diferença que não foi mencionada até agora é que uma visualização parcial não adiciona prefixos de modelo enquanto um modelo adiciona Aqui está o problema

erhan355
fonte