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

先到這里吧

原文鏈接:http://www.cnblogs.com/Clingingboy/archive/2010/12/20/1911388.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM