這是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的均可以稱之為內容模型的控件.如下
這里似乎看不到ContentPresenter的影子.下面來舉一些例子
一個ContentPresenter的例子
ContentPresenter可以直接在xaml中輸出,其視覺樹中包含一個TextBlock,在默認的WPF樣式定義中找不到任何關於ContentPresenter的樣式,說明了ContentPresenter並非是真正代碼邏輯與樣式分離的,而是在內部代碼中提供了一個默認的模板即呈現了TextBlock,如果在內部創建模板的話,一般均會采用FrameworkElementFactory創建根元素,但這種方式太過於復雜,適用於一些簡單默認操作,就如ContentPresenter內部的TextBlock.
那么問題出來了,為什么不直接用TextBlock呢,還要包裝一個ContentPresenter?
ContentPresenter與TextBlock
如要回答上面的問題,那么就猶如來討論兩者的區別,我們來看下TextBlock
<TextBlock Text="Hello"/>
TextBlock是一個真正以文字為主題的元素,而ContentPresenter的功能就不只呈現文字了(只補)
只不過默認是呈現文字而已,但兩者概念完全不同,Content屬性是object類型,而非string,可以自己以Content為數據源而重新定義模板(ContentTemplate),如下示例
這樣的話ContentPresenter將不再局限於文字的呈現.
下面來看看ContentControl與ContentPresenter的關系
ContentControl與ContentPresenter
先看一個被重新定義的的Button樣式
上面可以看到,使用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來綁定指定的源屬性
記住內容模型不僅僅只是呈現文字而已,如果只是為了呈現文字的話,是不需要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的默認容器
先到這里吧
原文鏈接:http://www.cnblogs.com/Clingingboy/archive/2010/12/20/1911388.html