這篇部落格是我再了解WPF模闆的時候寫的,其實不算是我寫的,而是我經常看的, 我隻不過修改了裡面的幾個句子而已,因為覺得原文很好,沁人心脾,是以就轉載到自己的部落格中,原文的位址也一并付出:
<a href="http://www.cnblogs.com/dingli/archive/2011/07/20/2112150.html">http://www.cnblogs.com/dingli/archive/2011/07/20/2112150.html</a>
<a href="http://www.cnblogs.com/lxblog/archive/2012/10/16/2726826.html">http://www.cnblogs.com/lxblog/archive/2012/10/16/2726826.html</a>
在WPF中有三大模闆ControlTemplate,ItemsPanelTemplate,DataTemplate.其中ControlTemplate和ItemsPanelTemplate是控件模闆,DataTemplate是資料模闆,他們都派生自FrameworkTemplate抽象類。
ControlTemplate:控件模闆主要有兩個重要屬性:VisualTree内容屬性和Triggers觸發器。所謂VisualTree(視覺樹),就是呈現我們所畫的控件。Triggers可以對我們的視覺樹上的元素進行一些變化。一般用于單内容控件。
畫一個按鈕模闆來舉例說明:
結果:

我們在ControlTemplate中畫了兩個橢圓,應用于所有的Button按鈕,但我們Button中有Content屬性(内容為Hello WPF),卻沒有顯示出來。因為這裡用ControlTemplate重寫了Button的樣式,是以我們要在ControlTemplate中增加ContentControl,通過ContentControl中的Content來綁定父容器的Content屬性。
這下内容出來了
我們來看一下,ContentControl繼承于Control的,用MSDN的話是:表示包含單項内容的控件、ContentControl 可以包含任何類型的公共語言運作庫對象。如下ContentControl類圖。
為了提高性能,我們可以用一個ControlPresenter來代替ContentControl,效果還是一樣,那他們有什麼差別呢?
來看下ControlPresenter這個類,它繼承于FreameworkElement,如下圖:
ControlPresenter 通常叫做内容占位符。是以我們可以看到
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"/>來代替<ContentControl VerticalAlignment="Center" HorizontalAlignment="Center" Content="{TemplateBinding Content}"/> 。這裡少了Content綁定父容器,因為ControlPresenter有個隐式的Content="{TemplateBinding Content}",也就是你可以寫也可以不寫它。
從他們的基類可以看出,ContentControl比ContentPresenter大多了。其實ControlPresenter是一個原始的建構塊,而ContentControl是一個帶控件模闆的成熟控件(裡面包含ControlPresenter)。
是以我們一般用ControlPresenter。
ControlTemplate的VisualTree我們講過了,下面看下他的trigger如何運用。
我們在原來的代碼中增加
當我們把滑鼠移上去的時候就會變成如下圖所示:
發揮我們的想象力,我們可以根據ControlTemplate做更多的特效。如下:
我們先講ItemTemplate。它一般用在多個内容控件的模闆。比如ListBox。
如下看ListBox應用ItemTemplate:
在xaml中:
在背景代碼我們給它一些圖檔來填充這個ListBox.
每一張圖檔就是一個Item。我們如果想讓圖檔以橫向顯示。一開始我以為用StackPanel的Orientation=”Horiziontal”,運作時發現這不正确,這樣的設定是把Items中某一個Item中的所有内容水準放置,而圖檔還是垂直排列,可以這樣了解,因為這個item現在包括一個Image和Textblock,因為這兩個是放在一個StackPanel中的,設定了Horiziontal,那麼Image和TextBlock就水準了,但是整體的沒有變化,如果要想得到預期的結果,這時就要用到ItemsPanelTemplate這個模闆了,我們在ListBox的樣式中增加如下紅色區域的代碼:
這裡在DataTemplate中加了StackPanel 為了說明加在這裡的效果隻是區分:單個item橫向和整個items橫向。
現在我們要想讓布局可以随着窗體寬度變化,我們隻要把ItemsPanelTemplate中的StackPanel 改成WrapPanel,并且設定ListBox的ScrollViewer.HorizontalScrollBarVisibility="Disabled",這樣才可以看到效果。
我們先構造一個TreeView
xaml中:
在開始加個Loaded="UserControl_Loaded"
背景代碼中:
沒有任何樣式的TreeView
下面我們如何運用ItemsPresenter和ContentPresenter來添加樣式。來實作下面這幅圖的效果
在TreeView中ItemsPresenter和ContentPresenter是什麼關系:<code>ContentPresenter</code>是用來顯示TreeView中Item的内容 。<code>ItemsPresenter</code>是用來顯示它的子項(Item的子項,也就是說child’s Items)。
看紅色代碼的部分,這裡ContentPresenter顯示了父容器的Header的内容,比如GrandFather,Father,Son.而ItemsPresenter則是否讓他顯示其子元素。比如GrandFather的子元素為Father,沒有設定<ItemsPresenter Grid.Row="1"/> 的話。子元素Father是不會顯示的。
這裡為了突出階層化,運用了ItemsPanelTemplate。最後我們在資源裡引用這個樣式。
DataTemplate就是顯示綁定資料對象的模闆。