ContentControl和ContentPresenter之间有什么区别?

232

我不确定什么时候应该使用ContentPresenter而不是ContentControl(反之亦然)。目前,我在我的DataTemplate中几乎一直使用ContentControl。什么情况下应该使用ContentPresenter?为什么?

6个回答

195

ContentControl 是包含其他元素并具有 Content 属性的控件的基类,例如 Button

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

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

我的经验法则(并非适用于每种情况,请根据实际情况斟酌):

  1. ControlTemplate 中使用 ContentPresenter
  2. ControlTemplate 之外(包括 DataTemplate 和模板之外),尽量不要使用它们。如果需要,应优先选择 ContentPresenter
  3. 如果要创建一个自定义的 "无样式" 控件来托管内容,并且不能通过更改现有控件的模板来获得相同的结果(这应该极其罕见),则应继承 ContentControl

1
这是否意味着,一般情况下,我应该在我的DataTemplates中使用ContentPresenter,因为它更轻量级(但在像这样使用DataTemplate时功能等效)?那么如果我正在编写一个新控件,只需使用ContentControl作为基类即可? - Wilka
2
我明白了,ContentPresenter应该在模板中使用而不是ContentControl,但为什么? - sll
36
@sll - ContentControl是显示“内容”的每个控件的基类(例如:Label),ContentPresenter是ContentControl在内部用于显示内容的代码。因此有以下三点区别:1. ContentPresenter更加轻量级;2. ContentPresenter专门用于在控件模板中使用;3. ContentPresenter可以直接使用,而ContentControl则专门设计为可扩展(从中继承)的。 - Nir
33
当涉及到设置Content属性时,ContentPresenter的行为与ContentControl不同。当您设置ContentPresenter的Content属性时,它的DataContext会更改以匹配Content属性,但是ContentControl的DataContext保持不变。如果您在ContentPresenter上使用绑定设置了其他属性,则此事很重要,因为一旦DataContext更改,所有绑定都将使用其作为源。 - user195275
我来晚了。非常好的解释@sll,谢谢!!!我通常这样想ContentPresenter:如果使用您的模板的控件具有Content属性(即是ContentControl),则在模板中ContentPresenter所在的位置呈现您在控件中指定的内容。 - KyleLib
显示剩余2条评论

26

ContentPresenter通常用于控件模板中,作为一个占位符,表示“在此放置实际内容”。

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


7
ContentPresenter不会导致DataTemplate被应用于其内容吗?这不是它的主要目的之一吗? - Drew Noakes
1
嗯...可能吧。不管怎样,Bea Stollnitz的解释比我的好多了 ;) - Thomas Levesque
2
您简明扼要的回答似乎很快地总结了它:我认为ContentPresenter的整个设计只是为了简单地“实现”DataTemplate的膨胀 - 它似乎只有一个任务,就是定位和膨胀模板,同时设置DataContext;然后尽可能地“消失”(虽然您仍然可以在膨胀的模板中绑定到环境属性,如TextElement属性,来自ContentPresenter)。您不需要担心其他事情,它只是以相对较轻的方式膨胀模板。(我正在寻找最瘦的!) - Steven Coco

12

我最近在博客上写了一篇关于这两个控件的帖子:

ContentPresenter vs ContentControl

ContentPresenter.ContentSource 是两个类之间最大的区别。 ContentSource 属性仅在 ControlTemplate 内有意义;它确定要将内容映射到哪个 TemplatedParent 属性。 例如,如果一个控件包含一个依赖属性 MyProperty1,则我们可能在其 ControlTemplate 中找到以下内容:

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

ContentPresenter的内容将接收MyProperty1的值。

请注意,如果属性名称为Content,则无需指定ContentSource,因为它是默认值。

对于了解angularJs的人:这类似于传递机制(transclude mecanism)。


2

这是一个老问题,但我刚刚完成了一个基于模板的通用应用程序动画瓷贴控件的开发。看看来自旧的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。如果您不需要单独的容器,则只需使用ControlTemplateControlPresenter来显示内容块,这至少是微软开发WP7/8 SDK时所做的。ContentControl也可用于显示内容,但此时它同时充当容器和呈现器。因此,在上面的示例代码中,它的目的被分为容器和呈现器。在动态示例中,您可以显示容器(它可以具有空背景或尚不存在的某些东西),然后动态填充它以呈现内容。容器具有尺寸(宽度、高度等),您可以在容器控件上放置这些属性,并在其上呈现内容。在示例中,ContentControl确定了如何处理呈现器内容。


0

ContentControl 是用于创建 WPF 自定义控件(不要与用户控件混淆)的类,因此它是您的顶级类。 ContentPresenter 就像任何其他“常规”控件一样。您可以在自定义或用户控件中使用它,在模板中使用它,或者仅在标记中使用它。


-1
有时候,举个例子比理论术语更容易理解。在微软网站上(向下滚动至底部:http://msdn.microsoft.com/en-us/library/system.windows.controls.contentpresenter(v=vs.110).aspx),它使用按钮作为示例。按钮具有ContentControl,允许您放置一个控件或自定义控件,可以是图像、文本、复选框、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(内容控件),它是一个(继承自)ContentControlButton有一个ContentPresenter。请注意,您可以使用标准的Button来实现这一点,无需自定义它。 - O. R. Mapper
但与此无关,这个答案并没有解释为什么不能像ContentPresenter一样在ControlTemplate中使用ContentControl来显示Button的内容,也没有解释为什么不能这样做。因此,它并没有回答问题。 - O. R. Mapper

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接