WPF的Presenter(ContentPresenter)

本文深入探讨了WPF中ContentPresenter与ContentControl的关系,解析了它们在内容模型中的作用及如何通过ContentPresenter实现控件的灵活展示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址:

这是2年前写了一篇文章

http://www.cnblogs.com/Clingingboy/archive/2008/07/03/wpfcustomcontrolpart-1.html

我们先来看MSDN对其的介绍

Displays the content of a ContentControl

似乎其是为ContentControl定身量做的.

为了理解这一点,首先我们要对WPF内容模型有所了解,上面这篇文章有提到过ContentControl继承自Control,多了Content属性,继承自ContentControl的均可以称之为内容模型的控件.如下

image

这里似乎看不到ContentPresenter的影子.下面来举一些例子

一个ContentPresenter的例子

image

ContentPresenter可以直接在xaml中输出,其视觉树中包含一个TextBlock,在默认的WPF样式定义中找不到任何关于ContentPresenter的样式,说明了ContentPresenter并非是真正代码逻辑与样式分离的,而是在内部代码中提供了一个默认的模板即呈现了TextBlock,如果在内部创建模板的话,一般均会采用FrameworkElementFactory创建根元素,但这种方式太过于复杂,适用于一些简单默认操作,就如ContentPresenter内部的TextBlock.

那么问题出来了,为什么不直接用TextBlock呢,还要包装一个ContentPresenter?

ContentPresenter与TextBlock

如要回答上面的问题,那么就犹如来讨论两者的区别,我们来看下TextBlock 

<span style="color:#333333"><span style="color:blue"><</span><span style="color:#a31515">TextBlock </span><span style="color:red">Text</span><span style="color:blue">="Hello"/>
</span></span>

 

 

 

TextBlock是一个真正以文字为主题的元素,而ContentPresenter的功能就不只呈现文字了(只补)

image

只不过默认是呈现文字而已,但两者概念完全不同,Content属性是object类型,而非string,可以自己以Content为数据源而重新定义模板(ContentTemplate),如下示例

image

这样的话ContentPresenter将不再局限于文字的呈现.

下面来看看ContentControl与ContentPresenter的关系

ContentControl与ContentPresenter

先看一个被重新定义的的Button样式

image

上面可以看到,使用ContentPresenter非常的方便,只要将ContentPresenter放在模板中即可,也不需要做任何的额外的绑定(难道不需要做吗?只不过ContentPresenter内部帮我们做了默认的绑定),但如果使用TextBlock呢?如下还是需要做绑定的

<span style="color:#333333">        <span style="color:blue"><</span><span style="color:#a31515">Style </span><span style="color:red">TargetType</span><span style="color:blue">="Button">
            <</span><span style="color:#a31515">Setter </span><span style="color:red">Property</span><span style="color:blue">="Template">
                <</span><span style="color:#a31515">Setter.Value</span><span style="color:blue">>
                    <</span><span style="color:#a31515">ControlTemplate </span><span style="color:red">TargetType</span><span style="color:blue">="Button">
                        <</span><span style="color:#a31515">TextBlock </span><span style="color:red">Text</span><span style="color:blue">="{</span><span style="color:#a31515">TemplateBinding </span><span style="color:red">Content</span><span style="color:blue">}"/>
                    </</span><span style="color:#a31515">ControlTemplate</span><span style="color:blue">>
                </</span><span style="color:#a31515">Setter.Value</span><span style="color:blue">>
            </</span><span style="color:#a31515">Setter</span><span style="color:blue">>
        </</span><span style="color:#a31515">Style</span><span style="color:blue">>
</span></span>

如上看来我们还不如说ContentControl是ContentPresenter的一个特例,而ContentPresente

ContentPresenter则是ContentControl的基础.为了适配ContentPresenter,ContentControl提供了内容模型的相关属性,本质上ContentPresenter并非仅仅只是用到ContentControl而已,ContentPresenter可以通过指定ContentSource来绑定指定的源属性

image

记住内容模型不仅仅只是呈现文字而已,如果只是为了呈现文字的话,是不需要ContentPresenter的

父子元素之间的关系(ItemsPresenter)

有时候控件并非维护本身逻辑,而是依赖于父子元素的,如了上诉的ContentPresenter,我们还有一个非常常用的ListBox控件,因为继承自ItemsControl,所以有一个ItemsPanel属性作为集合元素承载容器,但集合控件本身却不负责呈现控件,那么这个任务就留给了子元素ItemsPresenter,其实用也很简单,只要把ItemsPresenter放在内部模板中,那么ItemsPresenter则会去检测父元素是否为集合控件,然后将ItemsPanel添加到其内部视觉树当中

<span style="color:#333333">        <span style="color:blue"><</span><span style="color:#a31515">Style </span><span style="color:red">x</span><span style="color:blue">:</span><span style="color:red">Key</span><span style="color:blue">="{</span><span style="color:#a31515">x</span><span style="color:blue">:</span><span style="color:#a31515">Type </span><span style="color:red">ItemsControl</span><span style="color:blue">}"
           </span><span style="color:red">TargetType</span><span style="color:blue">="{</span><span style="color:#a31515">x</span><span style="color:blue">:</span><span style="color:#a31515">Type </span><span style="color:red">ItemsControl</span><span style="color:blue">}">
            <</span><span style="color:#a31515">Setter </span><span style="color:red">Property</span><span style="color:blue">="Template">
                <</span><span style="color:#a31515">Setter.Value</span><span style="color:blue">>
                    <</span><span style="color:#a31515">ControlTemplate </span><span style="color:red">TargetType</span><span style="color:blue">="{</span><span style="color:#a31515">x</span><span style="color:blue">:</span><span style="color:#a31515">Type </span><span style="color:red">ItemsControl</span><span style="color:blue">}">
                        <</span><span style="color:#a31515">Border </span><span style="color:red">Background</span><span style="color:blue">="{</span><span style="color:#a31515">TemplateBinding </span><span style="color:red">Background</span><span style="color:blue">}"
                            </span><span style="color:red">BorderBrush</span><span style="color:blue">="{</span><span style="color:#a31515">TemplateBinding </span><span style="color:red">BorderBrush</span><span style="color:blue">}"
                            </span><span style="color:red">BorderThickness</span><span style="color:blue">="{</span><span style="color:#a31515">TemplateBinding </span><span style="color:red">BorderThickness</span><span style="color:blue">}"
                            </span><span style="color:red">Padding</span><span style="color:blue">="{</span><span style="color:#a31515">TemplateBinding </span><span style="color:red">Padding</span><span style="color:blue">}"
                            </span><span style="color:red">SnapsToDevicePixels</span><span style="color:blue">="true">
                            <</span><span style="color:#a31515">ItemsPresenter </span><span style="color:red">SnapsToDevicePixels</span><span style="color:blue">="{</span><span style="color:#a31515">TemplateBinding </span><span style="color:red">SnapsToDevicePixels</span><span style="color:blue">}"/>
                        </</span><span style="color:#a31515">Border</span><span style="color:blue">>
                    </</span><span style="color:#a31515">ControlTemplate</span><span style="color:blue">>
                </</span><span style="color:#a31515">Setter.Value</span><span style="color:blue">>
            </</span><span style="color:#a31515">Setter</span><span style="color:blue">>
        </</span><span style="color:#a31515">Style</span><span style="color:blue">>
</span></span>

如下视觉树,StackPanel作为ItemsControl的默认容器

image

先到这里吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值