В чем разница между ContentControl и ContentPresenter?

208

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

Wilka
источник

Ответы:

164

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

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

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

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

  1. Внутри ControlTemplateиспользованияContentPresenter
  2. Вне ControlTemplate(включая DataTemplateи внешние шаблоны) старайтесь не использовать ни один из них, если вам нужно, вы должны предпочестьContentPresenter
  3. Подкласс, ContentControlесли вы создаете пользовательский элемент управления «без внешнего вида», который содержит содержимое, и вы не можете получить тот же результат, изменяя шаблон существующего элемента управления (это должно быть крайне редко).
Nir
источник
1
Означает ли это, что в общем случае мне следует использовать ContentPresenter внутри моих DataTemplates, потому что он более легкий (но функционально эквивалентный при использовании в DataTemplate, подобном этому)? Тогда просто используйте ContentControl в качестве базового класса, если я пишу новый элемент управления?
Wilka
Я отредактировал ответ с более подробной информацией, когда я буду использовать ContentPresenter и когда ContentControl
Nir
1
Хорошо, я понял, что ContentPresenter следует использовать в шаблонах вместо ContentControl, но почему?
SLL
32
@sll - ContentControl - это базовый класс для каждого элемента управления, который отображает «контент» (например, Label), ContentPresenter - это код, используемый внутренне ContentControl для отображения контента, поэтому: 1. ContentPresenter более легкий, 2. ContentPresenter предназначен для использоваться внутри шаблонов управления и 3. ContnetPresenter предназначен для использования как есть, а ContentControl предназначен для расширения (унаследованного от)
Nir
23
ContentPresenter ведет себя не так, как ContentControl, когда дело касается установки свойства Content. Когда вы устанавливаете свойство ContentPresenter, его DataContext изменяется в соответствии со свойством Content, но DataContext ContentControl остается неизменным. Это имеет значение, если у вас есть другие свойства в ContentPresenter, установленные через привязку, потому что, как только DataContext изменяется, все привязки используют его в качестве источника.
user195275
25

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

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

Томас Левеск
источник
6
Не приведет ли ContentPresenter к тому, что DataTemplate будет применен к его контенту? Разве это не одна из его основных целей?
Дрю Ноакс
1
ммм ... да, наверное. В любом случае, объяснение Беа Столльниц намного лучше моего;)
Томас Левеск
Ваш краткий ответ, казалось, быстро подытожил: я полагаю, что весь дизайн ContentPresenter состоит в том, чтобы просто «реализовать» инфляцию DataTemplate - кажется, что единственная задача состоит в том, чтобы просто найти и накачать шаблон, также задав DataContext; и попытка затем просто «исчезнуть», насколько это возможно (ТОГДА ВЫ ВСЕ ЕЩЕ МОЖЕТЕ связать в надутом шаблоне с окружающими свойствами, такими как свойства TextElement, которые затем поступают из ContentPresenter). Вам не нужно беспокоиться о других вещах, и это просто раздувает шаблон относительно тонким способом. (Я ищу самых худых!)
Стивен Коко
9

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

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

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

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

Контент ContentPresenter получит значение MyProperty1.

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

Для тех, кто знает angularJs: это похоже на включение механизма.

Чарльз ГЕТЬЕР
источник
2

Это старый вопрос, но я только заканчивал разработку анимированного Tile Control, шаблона, основанного на универсальном приложении, посмотрите на этот код из старого Phone 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 также можно использовать для отображения контента, но затем он служит как контейнером, так и презентатором. Таким образом, в приведенном выше примере кода его назначение разделено на Контейнер и Presenter. В динамических примерах вы можете отобразить контейнер (он может иметь пустой фон или что-то, чего еще нет), а затем динамически заполнить его содержимым презентатора. Контейнер имеет размеры (ширину, высоту и т. Д.), Вы помещаете эти свойства в элемент управления контейнера и представляете содержимое на нем. В примере ContentControl определяет, что должно быть сделано с содержимым презентатора.

Герман ван дер Блом
источник
1

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

После настройки кнопки, теперь на 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 позволяет только вводить текст.

Уэйн Ло
источник
2
ButtonНе имеет в [ ContentControl] (msdn.microsoft.com/en-us/library/system.windows.controls.contentcontrol (v = vs.110) .aspx), он является (наследует от) ContentControl. Button ИмеетContentPresenter . Обратите внимание, что вы можете сделать это со стандартом Button, не нужно настраивать его.
ИЛИ Mapper
Но не связанный с этим, этот ответ не объясняет, может ли и почему вместо ContentPresentera ContentControlне использоваться так же хорошо в ControlTemplateотображении содержания Button. Как таковой, он не отвечает на вопрос.
ИЛИ Mapper