回顧
上一篇,我們簡單介紹了幾個基本的控件,本節我們將講解每個控件的樣式的自定義和數據模板的自定義,我們會結合項目中的具體的要求和場景來分析,給出我們實現的方案和最終的運行效果。
本文大綱
1、控件模板及數據模板
2、ListBox深度定制模板。
3、TreeView高級模板使用實例。
控件模板及數據模板
控件模板
什么是控件模板,指定可以在控件的多個實例之間共享 Control 的可視結構和性能方面的方面。控件模板其實就是我們在可視方面的自定義模板,ControlTemplate 允許您指定控件的可視結構。 重寫 ControlTemplate 重新生成該控件的可視結構。
模板化控件是 WPF 提供的許多功能之一樣式設置和模板化模型。 該樣式和模板化模型提供了許多情況下您不需要編寫擁有控件這樣的大的靈活性。
控件模板包含二方面的內容:VisualTree和Tigger。本篇介紹的內容,完全都是基於這二塊的內容進行討論和說明。
什么是ViewTree
VisualTree就是對應WPF控件的可視元素的定義,下面來舉例說明:
上面,我們通過了lable重寫了button按鈕的控件模板,我們還可以采用更復雜的控件來重寫它:
運行后的效果效果就是上面的預覽圖,我們當然還可以構建更復雜的情況,WPF中基本上所有的控件,都可以定義控件模板。
上面的情況是我們針對一個按鈕重寫這樣的控件模板,如果我們一個頁面中有多個控件,並且這些控件的樣式都是一樣的,唯一的區別是控件的內容或文本不同而已,我們應該如何做呢?這個時候我們就需要把控件模板定義為資源,如下所示:
我們下面添加多個按鈕,來看看應用的具體效果:
夠簡單吧,其實很簡單,我們就可以重寫控件的模板了,好了,下面來看看更復雜一些的,我們可能想當鼠標滑過,或者按下后,按鈕有一個不同的樣式,這時候我們就會涉及到前面介紹的Tigger了,下面我們就來看看
具體的代碼如下:
在WPF中,為了提高用戶體驗的效果,實現界面特殊的效果,我們會大量的使用動畫來完成。
前面用了大量的篇幅來說明,控件模板和觸發器,實現界面的特殊的效果,使用WPF來做事非常的簡單。
在第二小節中,我們將會舉幾個例子來說明項目中的具體用法。
數據模板
數據模板與控件模板不同,主要是針對某種類型的數據而定制的模板,該模板會自動根據綁定的數據類型,在構造界面顯示時,根據預先設定的數據模板來組織頁面顯示的內容。數據模板和控件模板的定義差不多。我們先來定義一個數據模板,然后看看如何使用。
我們來看看代碼是如何設定的,才能實現,這樣的效果:
上面用到了,綁定,關於更多的綁定,我們在后面的MVVM的實例中大量的使用了綁定。
基於人員信息,構造人員信息綁定集合
將ViewModel與界面建立關聯關系
最后,采用ListBox來顯示數據項,通過數據綁定來實現
這里我們發現數據模板的效果,並不是非常的好看,這時候,我們可以采用樣式模板來完成樣式設定。
然后我們重新設置Listview的樣式后,運行:
F5運行后效果如下:
ListBox深度模板定制
定制Demo1
上面我們雖然應用了樣式,但是還是感覺不好看,而且鼠標點擊后沒有效果,是因為在觸發器中沒有做任何的效果設定。
我們如果在觸發器中修改為Button或者Border的背景色,再試試呢?
果然是我們想要的效果,那么我們來看看我們只需要在模板中書寫如下的簡單幾行代碼即可:
下面我們先來看看一個效果。
ListView具有黑色的背景。可以采用圖片或者顏色值
我們將上面的例子,一步步的實現這個效果。
哈哈,就是這個效果,其實實現起來非常的簡單,就是重寫控件模板即可:
接着:重寫觸發器,當鼠標滑過時的樣式
當鼠標獲得焦點也就是按下時的樣式。
設置Grid的樣式
只需要簡單的幾步,就完全可以實現一組特別不錯的效果。
上面我們把樣式都寫到頁面當中了,對於具體的情況,可能我們希望能夠將樣式通用,所以,我們會定義一個單獨的樣式文件,關於樣式文件,我們前面的文章中也有提到過,這里就不做特別的說明了。
下面我們來看看另外的一個效果:
對於這樣的效果,我們也可以通過ListBox來實現,無非就是重寫ListBox的控件模板
下面我們也來一步步的分析下效果的實現
選中后的高亮效果,無非就是設置邊框。
然后就是橫向顯示,需要重寫ListBox的ItemsPanel修改為WrapPanel。
這樣,我們的列表項就可以橫向顯示,然后設置每個列表項的樣式:
為了能夠看到Border的邊框,請設置borderThickness和顏色。
同時保持border內部的子控件與border的邊距值,否則出現不了,剛才展示的效果。
代碼本身就是這些東西,都是比較簡單的。
TreeView高級模板使用實例
Treeview的效果
首先給大家看看實現的具體效果。
上面的效果,還是不錯的,不過實現起來的難度就會大很多。
下面給出設計思路和具體的實現代碼。
我們實現的效果如上圖,屏蔽了原始的+-符號,太難看了,所以,我們重寫了相關的樣式和模板來達到上述的效果,下面給出具體的實現
A、先定義基本的ViewModel
具體的代碼,會提供下載
B、定義TreeView的數據庫結構
上面定義的ViewModel只是為了DataTemplate使用的,在DataTemplate那里一看就明白了。
修改原來的數據結構,如上。
添加一個負責界面綁定的ViewModel
public class PersonViewModelCollection : INotifyPropertyChanged
{
System.Collections.ObjectModel.ObservableCollection<ResourceSturctViewModel> persons =
new System.Collections.ObjectModel.ObservableCollection<ResourceSturctViewModel>();public PersonViewModelCollection()
{
Person tempA = new Person()
{
Address = "北京",
Name = "A",
Photo = "/Samples.04.Template;Component/Images/logo_small.gif",
Sex = "男"
};Person tempB = new Person()
{
Address = "北京",
Name = "B",
Photo = "/Samples.04.Template;Component/Images/logo_small.gif",
Sex = "未知"
};List<Person> tempABPersons = new List<Person>();
tempABPersons.Add(tempA);
tempABPersons.Add(tempB);
Person[] tempPersons = tempABPersons.ToArray();persons.Add(new ResourceSturctViewModel(new Person()
{
Address = "北京",
Name = "A",
Photo = "/Samples.04.Template;Component/Images/logo_small.gif",
Sex = "男",
Childerns = tempPersons}));
persons.Add(new ResourceSturctViewModel(new Person()
{
Address = "河北",
Name = "B",
Photo = "/Samples.04.Template;Component/Images/logo_small.gif",
Sex = "女",
Childerns = tempPersons
}));persons.Add(new ResourceSturctViewModel(new Person()
{
Address = "山西",
Name = "C",
Photo = "/Samples.04.Template;Component/Images/logo_small.gif",
Sex = "男",
Childerns = tempPersons
}));
}public System.Collections.ObjectModel.ObservableCollection<ResourceSturctViewModel> PersonList
{
get
{
return this.persons;
}
}#region INotifyPropertyChanged 成員
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
后台的相關代碼,都構建完畢了,下面我們就來看看界面的設計和組織了:
TreeView節點前的展開折疊樣式
TrewViewItem的每個節點項的樣式:
上面沒有設置具體的控件和綁定,而是通過ContentPresenter和ItemsHost來處理的,這樣我們就可以結合數據模板來做統一處理,最終將DataTemplate設置的控件自動顯示到當前的ContentPresenter和ItemsHost中。
如果不按照上述要求,那么當我們重寫TreeView時就會遇到很多莫名其妙的問題,我也是遇到了,才總結出來。
在前面的樣式中,我們加入了如下事件,務必寫上,這是為了觸發Lazyload的操作的。
等你自己試一遍,就會發現其實也不難,只要掌握了對自定義模板的規則,就完全可以自定義更復雜的樣式和效果。