欢迎光临
我们一直在努力

【笔记】在WPF中ContentPresenter详细功能介绍以及跟ContentControl的区别

1. ContentPresenter 是什么

ContentPresenter 是 WPF 中专门用来“显示内容”的元素。

它通常不单独作为业务控件使用,而是放在 ControlTemplate、DataTemplate、自定义控件模板中,用来把某个 Content 渲染出来。

常见位置:

<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}">
<ContentPresenter />
</Border>
</ControlTemplate>

这里的 ContentPresenter 负责显示 Button.Content。


2. ContentPresenter 的核心功能

2.1 显示任意内容

ContentPresenter.Content 可以是字符串、数字、对象、UI 元素等。

<ContentPresenter Content="Hello WPF" />

<ContentPresenter>
<ContentPresenter.Content>
<StackPanel>
<TextBlock Text="Title" />
<Button Content="OK" />
</StackPanel>
</ContentPresenter.Content>
</ContentPresenter>


2.2 使用 ContentTemplate

可以通过 ContentTemplate 指定内容显示方式。

<ContentPresenter Content="{Binding User}">
<ContentPresenter.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
<TextBlock Text="" />
<TextBlock Text="{Binding Age}" />
</StackPanel>
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>

如果 Content 是一个对象,ContentPresenter 会用 DataTemplate 把它显示出来。


2.3 使用 ContentTemplateSelector

当不同数据需要使用不同模板时,可以用 ContentTemplateSelector。

<ContentPresenter Content="{Binding CurrentItem}"
ContentTemplateSelector="{StaticResource MyTemplateSelector}" />

适合场景:

  • 不同类型数据使用不同 UI
  • 根据状态切换模板
  • 消息列表、动态表单、配置面板等

2.4 使用 ContentStringFormat

用于格式化内容。

<ContentPresenter Content="{Binding Price}"
ContentStringFormat="Price: {0:C}" />


2.5 在 ControlTemplate 中显示控件内容

这是最常见用法。

<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Button.Content 最终就是由 ContentPresenter 显示的。


3. ContentPresenter 常用属性

属性说明
Content 要显示的内容
ContentTemplate 内容模板
ContentTemplateSelector 内容模板选择器
ContentStringFormat 内容字符串格式
ContentSource 在模板中指定内容来源
RecognizesAccessKey 是否识别访问键,例如 _File

4. ContentSource 的作用

ContentSource 常用于 ControlTemplate 内部,用来告诉 ContentPresenter 应该显示模板宿主控件的哪个内容属性。

例如:

<ContentPresenter ContentSource="Content" />

它大致等价于:

<ContentPresenter Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"
ContentStringFormat="{TemplateBinding ContentStringFormat}" />

对于 ContentControl,默认就是显示 Content。

如果是类似 HeaderedContentControl,可以用:

<ContentPresenter ContentSource="Header" />

这会绑定到:

Header
HeaderTemplate
HeaderTemplateSelector
HeaderStringFormat


5. ContentPresenter 的内容显示规则

当 ContentPresenter 显示内容时,大致规则如下:

5.1 如果内容是 UIElement

直接显示该元素。

<ContentPresenter>
<ContentPresenter.Content>
<Button Content="Click Me" />
</ContentPresenter.Content>
</ContentPresenter>


5.2 如果设置了 ContentTemplate

使用 ContentTemplate 渲染。

<ContentPresenter Content="{Binding Person}"
ContentTemplate="{StaticResource PersonTemplate}" />


5.3 如果设置了 ContentTemplateSelector

由选择器决定使用哪个模板。

<ContentPresenter Content="{Binding Message}"
ContentTemplateSelector="{StaticResource MessageTemplateSelector}" />


5.4 如果没有模板

通常调用内容的 ToString() 显示。

<ContentPresenter Content="{Binding SomeObject}" />

如果 SomeObject.ToString() 返回 "abc",界面上就显示 abc。


6. ContentControl 是什么

ContentControl 是一个控件基类,用于承载单个内容。

常见继承自 ContentControl 的控件有:

ContentControl
├─ ButtonBase
│ ├─ Button
│ ├─ ToggleButton
│ └─ RepeatButton
├─ Label
├─ CheckBox
├─ RadioButton
├─ ToolTip
├─ GroupBox
├─ UserControl
└─ Window

它本身有 Content 属性:

<ContentControl Content="Hello" />

也可以承载复杂 UI:

<ContentControl>
<StackPanel>
<TextBlock Text="User Name" />
<TextBox />
</StackPanel>
</ContentControl>


7. ContentControl 常用功能

7.1 承载单个内容

<ContentControl Content="{Binding CurrentView}" />

常用于 MVVM 页面切换。


7.2 使用 ContentTemplate

<ContentControl Content="{Binding CurrentUser}">
<ContentControl.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>


7.3 使用 ContentTemplateSelector

<ContentControl Content="{Binding CurrentPage}"
ContentTemplateSelector="{StaticResource PageTemplateSelector}" />


7.4 作为自定义控件基类

如果一个控件只需要一个内容区域,可以继承 ContentControl。

public class CardControl : ContentControl
{
}

模板中通常放一个 ContentPresenter:

<Style TargetType="{x:Type local:CardControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CardControl}">
<Border Padding="12"
Background="White"
BorderBrush="Gray"
BorderThickness="1">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>


8. ContentPresenter 和 ContentControl 的区别

核心区别

对比项ContentControlContentPresenter
定位 控件 内容展示器
是否继承 Control
是否有控件模板 Template 没有 ControlTemplate
是否用于交互 可以 通常不用于交互
是否可作为控件基类 可以 通常不作为控件基类
主要用途 承载一个内容 在模板中显示内容
常见使用位置 页面、控件、布局中 ControlTemplate / DataTemplate 内部
是否拥有完整控件行为

简单理解

ContentControl

是一个“容器控件”。

<ContentControl Content="Hello" />

它本身是控件,负责承载内容、应用样式、使用控件模板。


ContentPresenter

是一个“内容显示占位符”。

<ContentPresenter Content="{TemplateBinding Content}" />

它主要负责把内容显示出来。


关系可以这样理解

很多 ContentControl 的默认模板内部都会包含一个 ContentPresenter。

ContentControl
└─ ControlTemplate
└─ ContentPresenter
└─ 显示 ContentControl.Content

也就是说:

  • ContentControl 拥有 Content
  • ContentPresenter 显示 Content

9. 示例:两者配合使用

自定义按钮模板

<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="LightBlue"
Padding="8"
CornerRadius="4">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

使用:

<Button Content="Save" />

这里:

  • Button 是 ContentControl
  • Button.Content 是 "Save"
  • ContentPresenter 负责显示 "Save"

10. 什么时候用 ContentControl

适合直接放在页面或控件中,用来显示某个内容。

场景 1:动态页面切换

<ContentControl Content="{Binding CurrentViewModel}" />

配合 DataTemplate:

<DataTemplate DataType="{x:Type vm:HomeViewModel}">
<views:HomeView />
</DataTemplate>

<DataTemplate DataType="{x:Type vm:SettingViewModel}">
<views:SettingView />
</DataTemplate>


场景 2:封装一个可承载内容的控件

<local:CardControl>
<TextBlock Text="Card Content" />
</local:CardControl>


场景 3:显示单个对象

<ContentControl Content="{Binding SelectedItem}"
ContentTemplate="{StaticResource DetailTemplate}" />


11. 什么时候用 ContentPresenter

适合在模板内部使用。

场景 1:自定义控件模板

<ControlTemplate TargetType="{x:Type local:CardControl}">
<Border>
<ContentPresenter />
</Border>
</ControlTemplate>


场景 2:显示模板宿主的内容

<ContentPresenter Content="{TemplateBinding Content}" />


场景 3:显示 Header

<ContentPresenter ContentSource="Header" />


12. 常见误区

误区 1:用 ContentPresenter 替代 ContentControl

如果是在页面中动态显示内容,通常用:

<ContentControl Content="{Binding CurrentView}" />

而不是:

<ContentPresenter Content="{Binding CurrentView}" />

虽然有时也能显示,但语义上 ContentControl 更合适。


误区 2:模板中忘记放 ContentPresenter

如果自定义 Button 模板时没有放 ContentPresenter:

<ControlTemplate TargetType="Button">
<Border Background="Red" />
</ControlTemplate>

那么:

<Button Content="OK" />

OK 不会显示。

应写:

<ControlTemplate TargetType="Button">
<Border Background="Red">
<ContentPresenter />
</Border>
</ControlTemplate>


误区 3:没有绑定内容对齐属性

自定义模板中如果写死:

<ContentPresenter />

可能导致 HorizontalContentAlignment、VerticalContentAlignment 不生效。

更完整写法:

<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />


13. 总结

ContentControl

用于“拥有并承载内容”。

ContentControl = 一个可以放内容的控件

适合:

  • 页面动态区域
  • 自定义内容控件
  • 承载单个对象或 UI
  • MVVM 页面切换

ContentPresenter

用于“把内容显示出来”。

ContentPresenter = 模板里的内容显示位置

适合:

  • ControlTemplate
  • DataTemplate
  • 自定义控件模板
  • 显示 Content、Header 等内容属性

最重要一句话

ContentControl 是控件,拥有 Content;ContentPresenter 是模板里的显示器,负责把 Content 呈现出来。

了解更多

ContentPresenter 类

ContentControl 类 | Microsoft Learn

System.Windows.Controls 命名空间 | Microsoft Learn

控件库 – WPF .NET Framework | Microsoft Learn

WPF 介绍 | Microsoft Learn

使用 Visual Studio 创建新应用教程 – WPF .NET | Microsoft Learn

https://github.com/HeBianGu

HeBianGu的个人空间-HeBianGu个人主页-哔哩哔哩视频

GitHub – HeBianGu/WPF-Control: WPF轻量控件和皮肤库

GitHub – HeBianGu/WPF-ControlBase: Wpf封装的自定义控件资源库

赞(0)
未经允许不得转载:171主机测评 » 【笔记】在WPF中ContentPresenter详细功能介绍以及跟ContentControl的区别
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址