¿Cuál es la diferencia entre ContentControl y ContentPresenter?

208

No estoy seguro de cuándo debo usar en ContentPresenterlugar de ContentControl(y viceversa). Por el momento, estoy usando ContentControlcasi todo el tiempo en mi DataTemplates. ¿Cuándo sería ContentPresenteruna mejor opción? ¿y por qué?

Wilka
fuente

Respuestas:

164

ContentControles una clase base para controles que contienen otros elementos y tienen una Contentpropiedad (por ejemplo Button).

ContentPresenter se usa dentro de plantillas de control para mostrar contenido.

ContentControl, cuando se usa directamente (se supone que debe usarse como una clase base), tiene una plantilla de control que usa ContentPresenter para mostrar su contenido.

Mis reglas generales (no aplicable en todos los casos, use su criterio):

  1. ControlTemplateUso interiorContentPresenter
  2. Fuera de ControlTemplate(incluidas DataTemplatey fuera de las plantillas) intente no usar ninguna de ellas, si es necesario, debeContentPresenter
  3. Subclase ContentControlsi está creando un control "sin apariencia" personalizado que aloja contenido y no puede obtener el mismo resultado cambiando la plantilla de un control existente (eso debería ser extremadamente raro).
Nir
fuente
1
¿Eso significa que, en general, probablemente debería usar ContentPresenter dentro de mis DataTemplates, porque es más liviano (pero funcionalmente equivalente cuando se usa en un DataTemplate como este)? ¿Entonces solo uso ContentControl como clase base si estoy escribiendo un nuevo control?
Wilka
He editado la respuesta con más detalles sobre cuándo usaría ContentPresenter y cuándo ContentControl
Nir
1
Ok, tengo idea de que ContentPresenter debe usarse en plantillas en lugar de ContentControl, pero ¿por qué?
sll
32
@sll - ContentControl es la clase base para cada control que muestra "contenido" (ejemplo: Etiqueta), ContentPresenter es el código utilizado internamente por ContentControl para mostrar el contenido, por lo tanto: 1. ContentPresenter es más liviano, 2. ContentPresenter está diseñado para se utilizará dentro de las plantillas de control y 3. ContnetPresenter está diseñado para usarse tal cual, mientras que ContentControl está diseñado para extenderse (heredado de)
Nir
23
ContentPresenter se comporta de manera diferente a ContentControl cuando se trata de tener establecida la propiedad Content. Cuando configura la propiedad ContentPresenter Content, su DataContext cambia para coincidir con la propiedad Content, pero el DataContext de ContentControl no se ve afectado. Esto es importante si tiene otras propiedades en ContentPresenter establecidas a través del enlace, porque una vez que DataContext cambia, todos los enlaces lo usan como fuente.
user195275
25

ContentPresenter se usa generalmente en un ControlTemplate, como un marcador de posición para decir "poner el contenido real aquí".

Un ContentControl se puede usar en cualquier lugar, no necesariamente en una plantilla. Recogerá cualquier DataTemplate definido para el tipo de contenido asignado.

Thomas Levesque
fuente
66
¿Un ContentPresenter no causaría que un DataTemplate se aplique a su contenido? ¿No es ese uno de sus propósitos principales?
Drew Noakes
1
mmm ... si, probablemente. De todos modos, la explicación de Bea Stollnitz es mucho mejor que la mía;)
Thomas Levesque
Su breve respuesta pareció resumirla rápidamente: creo que todo el diseño del ContentPresenter es simplemente "implementar" la inflación de DataTemplate --- parece tener el único trabajo de localizar e inflar la plantilla, configurando el DataContext también; e intentando simplemente "desaparecer" tanto como sea posible (AUNQUE TODAVÍA puedes enlazar dentro de la plantilla inflada a propiedades ambientales como las propiedades TextElement, que vienen desde ContentPresenter). No necesita preocuparse por otras cosas, y solo infla la plantilla de una manera relativamente delgada. (Estoy buscando el más delgado!)
Steven Coco
9

Recientemente escribí una publicación en mi blog sobre estos dos controles:

ContentPresenter vs ContentControl (EDITAR: enlace roto reemplazado por versión archivada).

El ContentPresenter.ContentSource es lo que realmente hace la mayor diferencia entre las dos clases. La propiedad ContentSource solo tiene sentido dentro de ControlTemplate; determina con qué propiedad TemplatedParent se debe asignar el contenido. Por ejemplo, si un control contiene una propiedad de dependencia MyProperty1, entonces podemos encontrar lo siguiente dentro de su ControlTemplate:

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

El contenido de ContentPresenter recibirá el valor de MyProperty1.

Tenga en cuenta que si el nombre de la propiedad es Content, no es necesario especificarlo, ContentSourceya que es el valor predeterminado.

Para aquellos que conocen angularJs: esto es similar al mecanismo de transcluir.

Charles HETIER
fuente
2

Es una pregunta antigua, pero estaba terminando de desarrollar una plantilla animada de Tile Control, basada en una aplicación universal, mira este código del antiguo SDK del teléfono WP7 / 8:

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

Aquí puede ver que ContentControl es el Contenedor y el Presentador para mostrar contenido. En la mayoría de los casos, ControlTemplate será el Contenedor, pero si lo desea en su ControlTemplateotro contenedor, puede colocar un Contenedor adicional: ContentControlen él y para presentar el contenido por separado ContentPresenter. Si no necesita un recipiente separado, simplemente use ControlTemplateyControlPresenterspor mostrar bloques de contenido, al menos eso es lo que hicieron los chicos de Microsoft cuando desarrollaron el SDK WP7 / 8. ContentControl también se puede usar para mostrar contenido, pero luego sirve como contenedor y presentador. Entonces, en el código de muestra anterior, su propósito se divide en Contenedor y Presentador. En las muestras dinámicas, puede mostrar el contenedor (puede tener un fondo vacío o algo que todavía no está allí) y luego llenarlo dinámicamente con el contenido del presentador. Un contenedor tiene dimensiones (ancho, alto, etc.), usted coloca esas propiedades en el control del contenedor y presenta el contenido en él. En la muestra, ContentControl determina qué se debe hacer con el contenido del presentador.

Herman Van Der Blom
fuente
1

A veces un ejemplo es más fácil que la jerga teórica. En un sitio web de MS (Desplácese hasta la parte inferior: http://msdn.microsoft.com/en-us/library/system.windows.controls.contentpresenter(v=vs.110).aspx ), utiliza un botón como un ejemplo. Un botón tiene un ContentControl, que le permite colocar un control o un control personalizado que podría ser una Imagen, Texto, CheckBox, StackPanel, Grid, lo que sea.

Después de la personalización de Button, ahora en Xaml, puede escribir

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

En el código de ejemplo anterior, "my: Button.Content" es ContentControl. El AnotherControl colocará lo que había especificado donde está ContentPresenter.

De manera similar, cuando compara TextBox y TextBlock, TextBox tiene un ContentPresenter para que usted pueda rellenar cosas como en el ejemplo de Button anterior, mientras que un TextBlock no. Un TextBlock solo le permite ingresar texto.

Wayne Lo
fuente
2
A Buttonno tiene un [ ContentControl] (msdn.microsoft.com/en-us/library/system.windows.controls.contentcontrol (v = vs.110) .aspx), es un (hereda de) ContentControl. El Button tiene un ContentPresenter. Tenga en cuenta que puede hacerlo con el estándar Button, sin necesidad de personalizarlo.
O Mapper
Pero sin relación con eso, esta respuesta no explica si y por qué, en lugar de ContentPresenter, a ContentControl, no podría usarse tan bien ControlTemplatepara mostrar el contenido de Button. Como tal, no responde la pregunta.
O Mapper