Какая разница между ContentControl и ContentPresenter?

Я не уверен, когда я должен использовать ContentPresenter вместо ContentControl (и наоборот). На данный момент я использую ContentControl почти все время в моем DataTemplate s. Когда лучше выбрать ContentPresenter? и почему?

Ответ 1

ContentControl - это базовый класс для элементов управления, которые содержат другие элементы, и содержат Content -property (например, Button).

ContentPresenter используется внутри шаблонов управления для отображения содержимого.

ContentControl, когда он используется напрямую (предполагается, что он используется как базовый класс), имеет шаблон управления, который использует ContentPresenter для отображения содержимого.

Мои правила (не применимы в каждом случае, используйте свое мнение):

  1. Внутри ControlTemplate используется ContentPresenter
  2. Вне ControlTemplate (включая DataTemplate и внешние шаблоны) старайтесь не использовать их, если вам нужно, вы должны предпочесть ContentPresenter
  3. Подкласс ContentControl если вы создаете настраиваемый "беззаботный" элемент управления содержимым хоста, и вы не можете получить тот же результат, изменив существующий шаблон управления (это должно быть крайне редко).

Ответ 2

ContentPresenter обычно используется в ControlTemplate, в качестве заполнителя, чтобы сказать "поместить здесь фактическое содержимое".

A ContentControl можно использовать где угодно, не обязательно в шаблоне. Он подберет любой DataTemplate, определенный для типа назначенного ему контента

Ответ 3

Недавно я написал сообщение в своем блоге об этих двух элементах управления:

ContentPresenter vs ContentControl (EDIT: неработающая ссылка заменена архивной версией.)

ContentPresenter.ContentSource - это то, что фактически делает большую разницу между этими двумя классами. Свойство ContentSource имеет смысл только внутри ControlTemplate; он определяет, для какого свойства TemplatedParent должен быть сопоставлен контент.  Например, если элемент управления содержит свойство зависимостей MyProperty1, тогда мы можем найти следующее в его ControlTemplate:

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

Содержимое ContentPresenter получит значение MyProperty1.

Обратите внимание, что если имя свойства Content, нет необходимости указывать ContentSource, поскольку это значение по умолчанию.

Для тех, кто знает angularJs: это похоже на transclude mecanism.

Ответ 4

Иногда пример проще, чем теоретический жаргон. На веб-сайте MS (прокрутите страницу вниз: http://msdn.microsoft.com/en-us/library/system.windows.controls.contentpresenter(v=vs.110).aspx), она использует кнопку в качестве примера. Кнопка имеет ContentControl, которая позволяет вам разместить один элемент управления или пользовательский элемент управления, который может быть изображением, текстом, CheckBox, StackPanel, Grid, независимо от того.

После настройки Button, теперь на Xaml вы можете написать

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

В приведенном выше примере код "my: Button.Content" - это ContentControl. AnotherControl будет использовать то, что вы указали, где находится ContentPresenter.

Аналогично, при сравнении TextBox и TextBlock у TextBox есть ContentPresenter, чтобы вы могли набивать в него вещи, как и предыдущий пример Button, тогда как TextBlock этого не делает. TextBlock позволяет вам вводить текст.

Ответ 5

Его старый вопрос, но я только что закончил разработку анимированного Tile Control, основанного на универсальном приложении шаблона, просмотрите этот код со старого телефона WP7/8 SDK:

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

Здесь вы можете видеть, что ContentControl - это Контейнер и Ведущий для отображения содержимого. В большинстве случаев ControlTemplate будет контейнером, но если вы хотите в своем ControlTemplate другом контейнере, вы можете добавить в него дополнительный контейнер: ContentControl и для представления содержимого отдельный ContentPresenter. Если вам не нужен отдельный контейнер, просто используйте ControlTemplate и ControlPresenters для отображения блоков контента, по крайней мере, того, что делали ребята из Microsoft при разработке WP7/8 SDK. ContentControl также может использоваться для отображения содержимого, но затем он служит как контейнером, так и ведущим. Таким образом, в образце кода выше его назначение разделяется на Container и Presenter. В динамических образцах вы можете отображать контейнер (он может иметь пустой фон или что-то еще не там), а затем динамически заполнять его содержимым ведущего. Контейнер имеет размеры (ширина, высота и т.д.), Вы помещаете эти свойства в элемент управления контейнера и представляете на нем контент. В образце ContentControl определяет, что должно быть сделано с содержимым презентатора.