Qual é a diferença entre ContentControl e ContentPresenter?

208

Não tenho certeza de quando devo usar em ContentPresentervez de ContentControl(e vice-versa). No momento, estou usando ContentControlpraticamente o tempo todo em meus DataTemplates. Quando seria ContentPresenteruma escolha melhor? e porque?

Wilka
fonte

Respostas:

164

ContentControlé uma classe base para controles que contêm outros elementos e têm uma Contentpropriedade-(por exemplo, Button).

ContentPresenter é usado dentro dos modelos de controle para exibir o conteúdo.

ContentControl, quando usado diretamente (deveria ser usado como uma classe base), possui um modelo de controle que usa o ContentPresenter para exibir seu conteúdo.

Minhas regras de ouro (não aplicável em todos os casos, use seu julgamento):

  1. ControlTemplateUso internoContentPresenter
  2. Fora de ControlTemplate(incluindo DataTemplatee fora de modelos) tente não usar nenhum deles, se necessário, você deve preferirContentPresenter
  3. Subclasse ContentControlse você estiver criando um controle "sem aparência" personalizado que hospeda o conteúdo e não pode obter o mesmo resultado alterando o modelo de um controle existente (isso deve ser extremamente raro).
Nir
fonte
1
Isso significa que, em geral, eu provavelmente deveria usar o ContentPresenter dentro dos meus DataTemplates, porque é mais leve (mas funcionalmente equivalente quando usado em um DataTemplate como este)? Em seguida, basta usar o ContentControl como classe base se estiver escrevendo um novo controle?
Wilka
Eu editei a resposta com mais detalhes quando eu usaria ContentPresenter e quando ContentControl
Nir
1
Ok, eu tenho a ideia de que o ContentPresenter deve ser usado em modelos em vez do ContentControl, mas por quê?
sll
32
@sll - ContentControl é a classe base para todo controle que exibe "conteúdo" (exemplo: Label), ContentPresenter é o código usado internamente pelo ContentControl para exibir o conteúdo - portanto: 1. ContentPresenter é mais leve, 2. ContentPresenter foi projetado para ser utilizado dentro de modelos de controlo e 3. ContnetPresenter está concebido para ser usado como está enquanto ContentControl é concebido para ser estendido (herdadas)
Nir
23
O ContentPresenter se comporta de maneira diferente do ContentControl quando se trata de ter a propriedade Content definida. Quando você define a propriedade ContentPresenter do Content, o DataContext muda para corresponder à propriedade Content, mas o DataContext do ContentControl permanece inalterado. Isso é importante se você tiver outras propriedades definidas no ContentPresenter por meio de associação, pois, quando o DataContext for alterado, todas as associações o usarão como origem.
user195275
25

O ContentPresenter geralmente é usado em um ControlTemplate, como um espaço reservado para dizer "coloque o conteúdo real aqui".

Um ContentControl pode ser usado em qualquer lugar, não necessariamente em um modelo. Ele selecionará qualquer DataTemplate definido para o tipo de conteúdo atribuído a ele

Thomas Levesque
fonte
6
Um ContentPresenter não faria com que um DataTemplate fosse aplicado a seu conteúdo? Esse não é um dos seus principais objetivos?
de Drew Noakes
1
mmm ... sim, provavelmente. De qualquer forma, a explicação de Bea Stollnitz é muito melhor do que o meu;)
Thomas Levesque
Sua resposta sucinta pareceu resumir rapidamente: acredito que todo o design do ContentPresenter é simplesmente "implementar" a inflação do DataTemplate - ele parece ter o único trabalho de localizar e inflar o modelo, configurando também o DataContext; e tentando "desaparecer" o máximo possível (ainda é possível vincular no modelo inflado a propriedades do ambiente, como propriedades TextElement, provenientes do ContentPresenter). Você não precisa se preocupar com outras coisas, e isso apenas infla o modelo de maneira relativamente reduzida. (Eu estou procurando o mais fino!)
Steven Coco
9

Recentemente, escrevi um post no meu blog sobre esses dois controles:

ContentPresenter vs ContentControl (EDIT: Link quebrado substituído pela versão arquivada.)

O ContentPresenter.ContentSource é o que realmente faz a maior diferença entre as duas classes. A propriedade ContentSource faz sentido apenas dentro de um ControlTemplate; determina com qual propriedade TemplatedParent o conteúdo deve ser mapeado. Por exemplo, se um controle contiver uma propriedade de dependência MyProperty1, poderemos encontrar o seguinte dentro dele ControlTemplate:

<ControlTemplate TargetType="MyControl" >
    [...]
       <ContentPresenter ContentSource="MyProperty1" />
    [...]
</ControlTemplate>

O conteúdo do ContentPresenter receberá o valor de MyProperty1.

Observe que, se o nome da propriedade for Content, não há necessidade de especificar ContentSource, pois é o valor padrão.

Para quem conhece Js angulares: isso é semelhante a transcluir o mecanismo.

Charles HETIER
fonte
2

É uma pergunta antiga, mas eu estava terminando o desenvolvimento de um controle de bloco animado, modelo baseado em um aplicativo universal, veja este código do antigo telefone WP7 / 8 SDK:

<ContentControl x:Name="contentControl" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch">
    <ContentPresenter x:Name="contentPresenter" CacheMode="BitmapCache"/>
</ContentControl>

Aqui você pode ver que o ContentControl é o Container e o Presenter para exibir o conteúdo. Na maioria dos casos, o ControlTemplate será o Container, mas se você quiser em ControlTemplateoutro container, poderá colocar um Container extra: ContentControlnele e para apresentar o conteúdo em separadoContentPresenter . Se você não precisar de um contêiner separado, use ControlTemplateeControlPresenterspara exibir blocos de conteúdo, pelo menos foi o que os funcionários da Microsoft fizeram quando desenvolveram o WP7 / 8 SDK. O ContentControl também pode ser usado para exibir conteúdo, mas serve como contêiner e apresentador. Portanto, no código de exemplo acima, seu objetivo é dividido em Container e Presenter. Em amostras dinâmicas, você pode exibir o contêiner (ele pode ter um plano de fundo vazio ou algo que ainda não existe) e preenchê-lo dinamicamente com o conteúdo do apresentador. Um contêiner possui dimensões (largura, altura etc.), você coloca essas propriedades no controle do contêiner e apresenta o conteúdo nele. Na amostra, o ContentControl determina o que deve ser feito com o conteúdo do apresentador.

Herman Van Der Blom
fonte
1

Às vezes, um exemplo é mais fácil que o jargão teórico. Em um site da Microsoft (role para a parte inferior: http://msdn.microsoft.com/en-us/library/system.windows.controls.contentpresenter(v=vs.110).aspx ), ele usa um botão como um exemplo. Um botão possui um ContentControl, que permite colocar um controle ou um controle personalizado que pode ser uma imagem, texto, caixa de seleção, StackPanel, grade, qualquer que seja.

Após a personalização do Button, agora no Xaml, você pode escrever

<my:Button>
   <my:Button.Content>
      <my:AnotherControl>
   </my:Button.Content>
</my:Button>

No código de exemplo acima, o "meu: Button.Content" é o ContentControl. O AnotherControl será o local que você especificou onde está o ContentPresenter.

Da mesma forma, quando se compara o TextBox e o TextBlock, o TextBox possui um ContentPresenter para você colocar coisas como o exemplo do botão acima, enquanto o TextBlock não. Um TextBlock permite apenas inserir texto.

Wayne Lo
fonte
2
A Buttonnão possui um [ ContentControl] (msdn.microsoft.com/en-us/library/system.windows.controls.contentcontrol (v = vs.110) .aspx), é um (herda de) ContentControl. O Button tem um ContentPresenter. Observe que você pode fazer isso com o padrão Button, sem necessidade de personalizá-lo.
OR Mapper
Mas, sem relação com isso, essa resposta não explica se e por que, em vez de ContentPresenter, a ContentControlnão poderia ser usado tão bem na ControlTemplateexibição do conteúdo do Button. Como tal, não responde à pergunta.
OR Mapper