1. DataTemplate和ControlTemplate的關系
? ? 學習過DataTemplate和ControlTemplate,你應該已經體會到,控件只是數據的行為和載體,是個抽象的概念,至于它本身長成什么樣子(控件內部結構),它的數據會長成什么樣子(數據顯示結構)都是靠Template生成的。決定控件外觀的是ControlTemplate,決定數據外觀的是DataTemplate,它們正是Control類的Template和ContentTemplate兩個屬性值
? ? 凡是Template,最終都要作用在控件上,這個控件就是Template的目標控件,也叫模板化控件。你可能會問:DataTemplate的目標應該是數據呀,怎么會是控件呢。DataTemplate給人的感覺的確是施加在數據對象上,但施加在數據對象上生成的一組控件總得有個載體吧?這個載體一般落實在一個叫做ContentPresenter對象上。ContentPresenter類只有ContentTemplate屬性、沒有Template屬性,這就證明了承載由DataTemplate生成的一組控件是他的專門用途。
? ? 至此我們可以看出,由ControlTemplate生成的控件樹其樹根就是ControlTemplate的目標控件,此模板化控件的Template屬性值就是一個ControlTemplate實例。與之相仿,由DataTemplate生成的控件其樹根是一個ContentPresenter控件,此模板化控件的ContentTemplate屬性值就是這個DataTemplate實例。因為ContentPresenter控件是ControlTemplate控件樹上的一個節點,所以DataTemplate控件樹是ControlTemplate里面的一個子樹。
? ? 顯然,如果把數據對象賦值給ContentPresenter的DataContext屬性,由DataTemplate生成的控件自然會找到這個數據對象并把它當作自己的數據源。
2. 應用
2.1 應用1
? ??
? ? 為Template設置其應用目標有兩種方法,一個是逐個設置控件的Template/ContentTemplate/ItemTemlate/CellTemplate等屬性,不想應用Template的控件不設置;另一種是整體應用,即把Template應用到某個類型的控件或者數據上。
把ControlTemplate應用到所有控件上需要借助Style來實現,但Style不能標記X:KEY,例如下面的代碼:
?
[html]?view plaincopy print?
<Window?x:Class="WpfApplication11.wnd11421"??????????xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"??????????xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"??????????Title="wnd11421"?Height="200"?Width="300">??????<Window.Resources>??????????????????<Style?TargetType="{x:Type?TextBox}">??????????????<Setter?Property="Template">??????????????????<Setter.Value>??????????????????????????????????????????<ControlTemplate?TargetType="{x:Type?TextBox}">??????????????????????????<Border?SnapsToDevicePixels="True"??????????????????????????????????Background="{TemplateBinding?Background}"??????????????????????????????????BorderBrush="{TemplateBinding?BorderBrush}"??????????????????????????????????BorderThickness="{TemplateBinding?BorderThickness}"??????????????????????????????????CornerRadius="5">??????????????????????????????<ScrollViewer?SnapsToDevicePixels="{TemplateBinding?SnapsToDevicePixels}"></ScrollViewer>??????????????????????????</Border>??????????????????????</ControlTemplate>??????????????????</Setter.Value>??????????????</Setter>??????????????<Setter?Property="Margin"?Value="5"></Setter>??????????????<Setter?Property="BorderBrush"?Value="Black"></Setter>??????????????<Setter?Property="Height"?Value="28"></Setter>??????????</Style>??????</Window.Resources>??????<StackPanel>??????????<TextBox></TextBox>??????????<TextBox></TextBox>??????????<TextBox?Style="{x:Null}"></TextBox>??????</StackPanel>??</Window>?? ? ? Style沒有X:key標記,默認為引用到所有的x:type指定的控件上,如果不想應用則將style標記為{x:null}。運行效果如下圖:
?
?
2.2 應用2
?
? ? 把DataTemplate應用到某個數據類型上是設置DataTemplate的DataType屬性,并且DataTemplate作為資源時也不能帶x:key標記, 例如下面的代碼:
?
[html]?view plaincopy print?
<Window?x:Class="WpfApplication11.wnd11422"??????????xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"??????????xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"??????????xmlns:local="clr-namespace:WpfApplication11"??????????Title="wnd11422"?Height="200"?Width="300">??????<Window.Resources>??????????????????<DataTemplate?DataType="{x:Type?local:Unit}">??????????????<Grid>??????????????????<StackPanel?Orientation="Horizontal">??????????????????????<Grid>??????????????????????????<Rectangle?Fill="Red"?Width="{Binding?Price}"?Stroke="Yellow"></Rectangle>??????????????????????????<TextBlock?Text="{Binding?Year}"/>??????????????????????</Grid>??????????????????????<TextBlock?Text="{Binding?Price}"></TextBlock>??????????????????</StackPanel>??????????????</Grid>??????????</DataTemplate>??????</Window.Resources>??????<StackPanel>??????????<ListBox?x:Name="_listBox"></ListBox>??????????<ComboBox?x:Name="_comBox"></ComboBox>??????</StackPanel>??</Window>?? ?
代碼中的DataTemplate的目標數據類型和ListBox的條目類型都是Unit:
?
[csharp]?view plaincopy print?
public?class?Unit??{??????public?int?Price?{?get;?set;?}??????public?string?Year?{?get;?set;?}??}?? 指定數據源:
?
?
[csharp]?view plaincopy print?
public?partial?class?wnd11422?:?Window??{??????public?wnd11422()??????{??????????InitializeComponent();????????????List<Unit>?_listUnit?=?new?List<Unit>()??????????{??????????????new?Unit(){Price=100,?Year="2001"?},??????????????new?Unit(){Price=120,?Year="2002"?},??????????????new?Unit(){Price=140,?Year="2003"?},??????????????new?Unit(){Price=180,?Year="2004"?},??????????????new?Unit(){Price=150,?Year="2005"?},??????????????new?Unit(){Price=200,?Year="2006"?},??????????};????????????_listBox.ItemsSource?=?_listUnit;??????????_comBox.ItemsSource?=?_listUnit;??????}??}?? 此時DataTemplate會自動加載到所有的Unit類型對象上,盡管我沒有為ListBox和CompBox指定ItemTemplate,一樣會得到下圖的效果:
?
2.3 應用3
?
? ? 很多時候數據是以XML形式存取的,如果把XML節點先轉換為CLR數據類型再應用DataTemplate就麻煩了。DataTemplate很智能,具有直接把XML數據節點當作目標對象的功能-----XML數據中的元素名(標簽名)可以作為DataType,元素的子節點和Attribute可以使用XPath來訪問。下面的代碼使用XmlDataProvider作為數據源(其XPath指出的必須是一組節點),請注意細節之處的變化,結果和應用2的效果相同:
?
[html]?view plaincopy print?
<Window?x:Class="WpfApplication11.wnd11423"??????????xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"??????????xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"??????????Title="wnd11423"?Height="200"?Width="300">??????<Window.Resources>??????????????????<DataTemplate?DataType="XUnit">??????????????<Grid>??????????????????<StackPanel?Orientation="Horizontal">??????????????????????<Grid>??????????????????????????<Rectangle?Fill="Red"?Width="{Binding?XPath=@Price}"?Stroke="Yellow"></Rectangle>??????????????????????????<TextBlock?Text="{Binding?XPath=@Year}"/>??????????????????????</Grid>??????????????????????<TextBlock?Text="{Binding?XPath=@Price}"></TextBlock>??????????????????</StackPanel>??????????????</Grid>??????????</DataTemplate>??????????????????<XmlDataProvider?x:Key="ds"?XPath="XUnits/XUnit">??????????????<x:XData>??????????????????<XUnits?xmlns="">??????????????????????<XUnit?Price="100"?Year="2001"></XUnit>??????????????????????<XUnit?Price="120"?Year="2002"></XUnit>??????????????????????<XUnit?Price="140"?Year="2003"></XUnit>??????????????????????<XUnit?Price="180"?Year="2004"></XUnit>??????????????????????<XUnit?Price="150"?Year="2005"></XUnit>??????????????????????<XUnit?Price="200"?Year="2006"></XUnit>??????????????????</XUnits>??????????????</x:XData>??????????</XmlDataProvider>??????</Window.Resources>??????<StackPanel>??????????????????<ListBox?x:Name="_listBox"?ItemsSource="{Binding?Source={StaticResource?ds}}"></ListBox>??????????<ComboBox?x:Name="_comBox"?ItemsSource="{Binding?Source={StaticResource?ds}}"></ComboBox>??????</StackPanel>??</Window>?? ?
?
2.4 應用4
?
? ? XML的優勢就是可以方便的表示帶有層級的數據,比如:年級----班級----小組 或 ?主菜單---次菜單----三級菜單。同時WPF準備了TreeView和MenuItem控件來顯示層級數據。能夠幫助層級控件顯示層級數據的模板是HierachicalDataTemplate。下面是實際工作中常見的例子:
? ? 值得一提的是,HierarchicalDataTemplate的作用不是MenuItem的內容而是它的Header。如果對MenuItem的單擊事件進行偵聽處理,我們就可以從被單擊的MenuItem的Header中取出XML數據。
?
[html]?view plaincopy print?
<Window?x:Class="WpfApplication11.wnd11424"??????????xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"??????????xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"??????????Title="wnd11424"?Height="400"?Width="300">??????<Window.Resources>??????????????????<HierarchicalDataTemplate?DataType="Grade"?ItemsSource="{Binding?XPath=Class}">??????????????<TextBlock?Text="{Binding?XPath=@Name}"></TextBlock>??????????</HierarchicalDataTemplate>??????????????????<HierarchicalDataTemplate?DataType="Class"?ItemsSource="{Binding?XPath=Group}">??????????????<RadioButton?Content="{Binding?XPath=@Name}"></RadioButton>??????????</HierarchicalDataTemplate>??????????????????<HierarchicalDataTemplate?DataType="Group">??????????????<CheckBox?Content="{Binding?XPath=@Name}"></CheckBox>??????????</HierarchicalDataTemplate>????????????????????<XmlDataProvider?x:Key="ds"?XPath="Data/Grade">??????????????<x:XData>??????????????????<Data?xmlns="">??????????????????????<Grade?Name="一年級">??????????????????????????<Class?Name="甲班">??????????????????????????????<Group?Name="A組"></Group>??????????????????????????????<Group?Name="B組"></Group>??????????????????????????????<Group?Name="C組"></Group>??????????????????????????</Class>??????????????????????????<Class?Name="乙班">??????????????????????????????<Group?Name="A組"></Group>??????????????????????????????<Group?Name="B組"></Group>??????????????????????????????<Group?Name="C組"></Group>??????????????????????????</Class>??????????????????????</Grade>??????????????????????<Grade?Name="二年級">??????????????????????????<Class?Name="丙班">??????????????????????????????<Group?Name="A組"></Group>??????????????????????????????<Group?Name="B組"></Group>??????????????????????????????<Group?Name="C組"></Group>??????????????????????????</Class>??????????????????????????<Class?Name="丁班">??????????????????????????????<Group?Name="A組"></Group>??????????????????????????????<Group?Name="B組"></Group>??????????????????????????????<Group?Name="C組"></Group>??????????????????????????</Class>??????????????????????</Grade>??????????????????</Data>??????????????</x:XData>??????????</XmlDataProvider>??????</Window.Resources>??????????<StackPanel?MenuItem.Click="StackPanel_Click">??????????<Menu?ItemsSource="{Binding?Source={StaticResource?ds}}"></Menu>??????????<TreeView?ItemsSource="{Binding?Source={StaticResource?ds}}"?Margin="5"></TreeView>??????</StackPanel>??</Window>?? 事件處理器:
?
?
[csharp]?view plaincopy print?
private?void?StackPanel_Click(object?sender,?RoutedEventArgs?e)??{??????????XmlElement?xmlElem?=?(e.OriginalSource?as?MenuItem).Header?as?XmlElement;??????MessageBox.Show(xmlElem.Attributes["Name"].Value);??}?? ?
?
?
轉載于:https://www.cnblogs.com/lizhenlin/p/5906678.html
總結
以上是生活随笔為你收集整理的WPF Template模版之DataTemplate与ControlTemplate的关系和应用【二】的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。