ContentControl和ContentPresenter有什么区别?


208

我不确定何时应该使用ContentPresenter代替ContentControl(反之亦然)。此刻,我ContentControl几乎一直都在使用DataTemplates。什么时候会ContentPresenter是更好的选择?为什么呢?

Answers:


164

ContentControl是包含其他元素并具有Content-property(例如Button)的控件的基类。

ContentPresenter 用于控件模板内部以显示内容。

ContentControl直接使用(应该用作基类)时,具有一个使用ContentPresenter来显示其内容的控件模板。

我的经验法则(并非在所有情况下都适用,请根据您的判断):

  1. 内部ControlTemplate使用ContentPresenter
  2. 在外部ControlTemplate(包括DataTemplate外部模板)中,尽量不要使用其中的任何一个,如果需要,您必须更喜欢ContentPresenter
  3. ContentControl如果要创建一个托管内容的自定义“无外观”控件,则为子类,而通过更改现有控件的模板(这非常少),您将无法获得相同的结果。

1
通常,这是否意味着我应该在DataTemplates中使用ContentPresenter,因为它重量更轻(但在像这样的DataTemplate中使用时功能上等效)?然后,如果我要编写新控件,只需将ContentControl用作基类?
威尔卡

当我使用ContentPresenter以及ContentControl时,我已经编辑了更详细的答案
-Nir

1
好的,我知道应该在模板中使用ContentPresenter而不是ContentControl,但是为什么?
sll

32
@sll-ContentControl是每个显示“内容”的控件的基类(例如:Label),ContentPresenter是ContentControl内部用于显示内容的代码-因此:1. ContentPresenter更轻巧,2. ContentPresenter设计为内部控制模板,并3. ContnetPresenter被设计成原样使用而ContentControl中被设计成延伸(从继承)
尼尔

23
在设置Content属性时,ContentPresenter的行为与ContentControl不同。设置ContentPresenter的Content属性时,其DataContext会更改为与Content属性匹配,但ContentControl的DataContext不会受到影响。如果通过绑定设置了ContentPresenter的其他属性,则这很重要,因为一旦DataContext更改,所有绑定都将其用作源。
user195275 2014年

25

ContentPresenter通常在ControlTemplate中使用,用作占位符,表示“将实际内容放在此处”。

ContentControl可以在任何地方使用,而不必在模板中使用。它将拾取为分配给它的内容类型定义的任何DataTemplate


6
ContentPresenter也不会导致将DataTemplate应用于其内容吗?这不是主要目的之一吗?
Drew Noakes

1
嗯...是的,可能 无论如何,Bea Stollnitz的解释比我的解释要好得多;)
Thomas Levesque

您的简洁答案似乎很快就可以总结出来:我相信ContentPresenter的整个设计就是简单地“实现” DataTemplate膨胀-似乎唯一的任务就是定位并膨胀模板,同时设置DataContext。然后尝试尽可能地“消失”(您仍然可以在膨胀的模板中将其绑定到诸如TextElement属性之类的环境属性,然后再从ContentPresenter中获得)。您无需担心其他事情,它只是以一种相对苗条的方式使模板膨胀。(我正在寻找最苗条的人!)
史蒂芬·可可

9

我最近在自己的博客上针对这两个控件写了一篇文章:

ContentPresenter与ContentControl(编辑:断开的链接已替换为存档版本。)

实际上,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将是Container,但是如果您想要在ControlTemplate另一个容器中,则可以放置一个额外的Container ContentControl:,并在其中单独显示内容ContentPresenter。如果您不需要单独的容器,则只需使用ControlTemplateControlPresenters用于显示内容块至少是Microsoft的家伙在开发WP7 / 8 SDK时所做的。ContentControl也可以用于显示内容,但随后既用作容器又用作演示者。因此,在上面的示例代码中,其目的在Container和Presenter中进行了划分。在动态示例中,您可以显示容器(它可以有一个空的背景或还没有的背景),然后用演示者内容动态地填充它。容器具有尺寸(宽度,高度等),您可以将这些属性放在容器控件上并在其上显示内容。在示例中,ContentControl确定必须对演示者内容执行的操作。


1

有时一个例子比理论上的术语容易。在MS网站(滚动到底部:http : //msdn.microsoft.com/zh-cn/library/system.windows.controls.contentpresenter (v= vs.110 ) .aspx)中,它使用按钮作为一个例子。按钮具有ContentControl,可让您放置一个控件或自定义控件,该控件可以是Image,Text,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仅允许您输入文本。


2
Button具有一个[ ContentControl](msdn.microsoft.com/en-us/library/system.windows.controls.contentcontrol(V = vs.110)的.aspx),它是一个(继承)ContentControl。该Button 一个ContentPresenter。请注意,您可以使用standard来做到这一点Button,而无需对其进行自定义。
OR Mapper

但与此无关的是,此答​​案不能解释是否以及为什么不能代替ContentPresentera ContentControl来很好地用于ControlTemplate显示的内容Button。因此,它不能回答问题。
OR Mapper
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.