• WPF的Presenter(ContentPresenter)


    这是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

    <TextBlock Text="Hello"/>
    

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

    image

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

    image

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

    下面来看看ContentControl与ContentPresenter的关系

    ContentControl与ContentPresenter

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

    image

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

            <Style TargetType="Button">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="Button">
                            <TextBlock Text="{TemplateBinding Content}"/>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
    

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

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

    image

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

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

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

            <Style x:Key="{x:Type ItemsControl}"
               TargetType="{x:Type ItemsControl}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ItemsControl}">
                            <Border Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                Padding="{TemplateBinding Padding}"
                                SnapsToDevicePixels="true">
                                <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
    

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

    image

    先到这里吧

  • 相关阅读:
    [crontab]修改默认编辑器
    [mysql]忘记用户密码或者误删用户账号
    [vim]多行注释和多行删除
    [mysql]my.cnf在哪里
    [python]有中文字符程序异常的解决方案
    [Linux]虚拟机无法安装deepin15.9的解决方案
    Elasticsearch5.X IN Windows 10 系列文章(2)
    Elasticsearch5.X IN Windows 10 系列文章(1)
    HTTP Error 502.5
    centos7 yum install redis
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/1911388.html
Copyright © 2020-2023  润新知