Quelle est la différence entre ContentControl et ContentPresenter?

208

Je ne sais pas quand je devrais utiliser à la ContentPresenterplace de ContentControl(et vice-versa). En ce moment, j'utilise à ContentControlpeu près tout le temps dans mon DataTemplates. Quel serait ContentPresenterle meilleur choix? et pourquoi?

Wilka
la source

Réponses:

164

ContentControlest une classe de base pour les contrôles qui contiennent d'autres éléments et ont une Contentpropriété (par exemple, Button).

ContentPresenter est utilisé dans les modèles de contrôle pour afficher le contenu.

ContentControl, lorsqu'il est utilisé directement (il est censé être utilisé comme classe de base), possède un modèle de contrôle qui utilise ContentPresenter pour afficher son contenu.

Mes règles de base (ne s'appliquent pas dans tous les cas, utilisez votre jugement):

  1. ControlTemplateUtilisation intérieureContentPresenter
  2. En dehors de ControlTemplate(y compris DataTemplateet en dehors des modèles) essayez de ne pas utiliser l'un d'eux, si vous en avez besoin, vous devez préférerContentPresenter
  3. Sous ContentControl- classe si vous créez un contrôle personnalisé "sans apparence" qui héberge du contenu et que vous ne pouvez pas obtenir le même résultat en modifiant le modèle d'un contrôle existant (cela devrait être extrêmement rare).
Nir
la source
1
Cela signifie-t-il qu'en général, je devrais probablement utiliser ContentPresenter dans mes DataTemplates, car il est plus léger (mais fonctionnellement équivalent lorsqu'il est utilisé dans un DataTemplate comme celui-ci)? Ensuite, utilisez simplement ContentControl comme classe de base si j'écris un nouveau contrôle?
Wilka
J'ai édité la réponse avec plus de détails quand j'utiliserais ContentPresenter et quand ContentControl
Nir
1
Ok, j'ai eu l'idée que ContentPresenter devrait être utilisé dans les modèles au lieu de ContentControl, mais pourquoi?
sll
32
@sll - ContentControl est la classe de base pour chaque contrôle qui affiche le "contenu" (exemple: Label), ContentPresenter est le code utilisé en interne par ContentControl pour afficher le contenu - donc: 1. ContentPresenter est plus léger, 2. ContentPresenter est conçu pour être utilisé dans des modèles de contrôle et 3. ContnetPresenter est conçu pour être utilisé tel quel tandis que ContentControl est conçu pour être étendu (hérité de)
Nir
23
ContentPresenter se comporte différemment de ContentControl lorsqu'il s'agit de définir la propriété Content. Lorsque vous définissez la propriété Content de ContentPresenter, son DataContext change pour correspondre à la propriété Content, mais le DataContext de ContentControl reste inchangé. Cela est important si vous avez d'autres propriétés sur ContentPresenter définies via la liaison, car une fois DataContext modifié, toutes les liaisons l'utilisent comme source.
user195275
25

ContentPresenter est généralement utilisé dans un ControlTemplate, comme un espace réservé pour dire "mettez le contenu réel ici".

Un ContentControl peut être utilisé n'importe où, pas nécessairement dans un modèle. Il récupérera tout DataTemplate défini pour le type de contenu qui lui est attribué

Thomas Levesque
la source
6
Un ContentPresenter ne provoquerait-il pas également l'application d'un DataTemplate à son contenu? N'est-ce pas l'un de ses principaux objectifs?
Drew Noakes
1
mmm ... ouais, probablement. Quoi qu'il en soit, l'explication de Bea Stollnitz est bien meilleure que la mienne;)
Thomas Levesque
Votre réponse succincte a semblé résumer rapidement: je crois que la conception entière du ContentPresenter consiste simplement à «implémenter» l'inflation DataTemplate --- il semble avoir le seul travail de localiser et de gonfler le modèle, en définissant également le DataContext; et en essayant ensuite de "disparaître" autant que possible (bien que vous puissiez toujours vous lier dans le modèle gonflé aux propriétés ambiantes comme les propriétés TextElement, provenant alors du ContentPresenter). Vous n'avez pas à vous soucier d'autres choses, et cela gonfle simplement le modèle d'une manière relativement mince. (Je cherche le plus mince!)
Steven Coco
9

J'ai récemment écrit un article sur mon blog concernant ces deux contrôles:

ContentPresenter vs ContentControl (EDIT: lien brisé remplacé par une version archivée.)

Le ContentPresenter.ContentSource est ce qui fait la plus grande différence entre les deux classes. La propriété ContentSource n'a de sens que dans un ControlTemplate; il détermine avec quelle propriété TemplatedParent le contenu doit être mappé. Par exemple, si un contrôle contient une propriété de dépendance MyProperty1, nous pouvons trouver ce qui suit dans son ControlTemplate:

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

Le contenu de ContentPresenter recevra la valeur de MyProperty1.

Veuillez noter que si le nom de la propriété est Content, il n'est pas nécessaire de le spécifier ContentSourcecar il s'agit de la valeur par défaut.

Pour ceux qui connaissent les angularJs: ceci est similaire au mécanisme de transclusion.

Charles HETIER
la source
2

C'est une vieille question mais je finissais juste de développer un Tile Control animé, un modèle basé sur une application universelle, regardez ce code de l'ancien SDK Phone WP7 / 8:

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

Ici, vous pouvez voir que ContentControl est le conteneur et le présentateur pour afficher le contenu. Dans la plupart des cas, le ControlTemplate sera le conteneur, mais si vous le souhaitez dans votre ControlTemplateautre conteneur, vous pouvez mettre un conteneur supplémentaire: ContentControlà l'intérieur et pour présenter le contenu séparément ContentPresenter. Si vous n'avez pas besoin d'un conteneur séparé, utilisez simplement ControlTemplateetControlPresenterspour afficher les blocs de contenu au moins c'est ce que les gars de Microsoft ont fait lorsqu'ils ont développé le SDK WP7 / 8. ContentControl peut également être utilisé pour afficher du contenu, mais il sert à la fois de conteneur et de présentateur. Ainsi, dans l'exemple de code ci-dessus, son objectif est divisé en conteneur et présentateur. Dans les échantillons dynamiques, vous pouvez afficher le conteneur (il peut avoir un arrière-plan vide ou quelque chose qui n'y est pas encore), puis le remplir dynamiquement avec le contenu du présentateur. Un conteneur a des dimensions (largeur, hauteur, etc.), vous mettez ces propriétés sur le contrôle de conteneur et présentez le contenu dessus. Dans l'exemple, ContentControl détermine ce qui doit être fait avec le contenu du présentateur.

Herman Van Der Blom
la source
1

Parfois, un exemple est plus facile que le jargon théorique. Dans un site Web MS (faites défiler vers le bas: http://msdn.microsoft.com/en-us/library/system.windows.controls.contentpresenter(v=vs.110).aspx ), il utilise un bouton comme un exemple. Un bouton a un ContentControl, qui vous permet de placer un contrôle ou un contrôle personnalisé qui pourrait être une image, du texte, une case à cocher, StackPanel, une grille, peu importe.

Après la personnalisation de Button, maintenant sur le Xaml, vous pouvez écrire

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

Dans l'exemple de code ci-dessus, le "my: Button.Content" est le ContentControl. Le AnotherControl sera placé à ce que vous avez spécifié où se trouve ContentPresenter.

De même, lors de la comparaison de TextBox et TextBlock, TextBox a un ContentPresenter pour que vous puissiez y ajouter des choses comme l'exemple Button ci-dessus, contrairement à TextBlock. Un TextBlock vous permet uniquement de saisir du texte.

Wayne Lo
la source
2
A Buttonne pas avoir un [ ContentControl] (msdn.microsoft.com/en-us/library/system.windows.controls.contentcontrol (v = vs.110) .aspx), il est un (hérite de) ContentControl. Le Button a unContentPresenter . Notez que vous pouvez le faire avec la norme Button, pas besoin de la personnaliser.
OR Mapper
Mais sans rapport avec cela, cette réponse n'explique pas si et pourquoi, au lieu du ContentPresenter, un ContentControlne pourrait pas être utilisé aussi bien dans le ControlTemplatepour afficher le contenu du Button. En tant que tel, il ne répond pas à la question.
OR Mapper