【轉】WPF Template模版之DataTemplate與ControlTemplate的關係和應用(二)

1. DataTemplate和ControlTemplate的關係

    學習過DataTemplate和ControlTemplate,你應該已經體會到,控件只是數據的行爲和載體,是個抽象的概念,至於它自己長成什麼樣子(控件內部結構),它的數據會長成什麼樣子(數據顯示結構)都是靠Template生成的。決定控件外觀的是ControlTemplate,決定數據外觀的是DataTemplate,它們正是Control類的Template和ContentTemplate兩個屬性值html

    凡是Template,最終都要做用在控件上,這個控件就是Template的目標控件,也叫模板化控件。你可能會問:DataTemplate的目標應該是數據呀,怎麼會是控件呢。DataTemplate給人的感受的確是施加在數據對象上,但施加在數據對象上生成的一組控件總得有個載體吧?這個載體通常落實在一個叫作ContentPresenter對象上。ContentPresenter類只有ContentTemplate屬性、沒有Template屬性,這就證實了承載由DataTemplate生成的一組控件是他的專門用途。ide

    至此咱們能夠看出,由ControlTemplate生成的控件樹其樹根就是ControlTemplate的目標控件,此模板化控件的Template屬性值就是一個ControlTemplate實例。與之相仿,由DataTemplate生成的控件其樹根是一個ContentPresenter控件,此模板化控件的ContentTemplate屬性值就是這個DataTemplate實例。由於ContentPresenter控件是ControlTemplate控件樹上的一個節點,因此DataTemplate控件樹是ControlTemplate裏面的一個子樹。學習

    顯然,若是把數據對象賦值給ContentPresenter的DataContext屬性,由DataTemplate生成的控件天然會找到這個數據對象並把它看成本身的數據源。spa

2. 應用


2.1 應用1code

    

    爲Template設置其應用目標有兩種方法,一個是逐個設置控件的Template/ContentTemplate/ItemTemlate/CellTemplate等屬性,不想應用Template的控件不設置;另外一種是總體應用,即把Template應用到某個類型的控件或者數據上。
把ControlTemplate應用到全部控件上須要藉助Style來實現,但Style不能標記X:KEY,例以下面的代碼:xml

<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>  
        <!--ControlTemplate做用在全部目標控件上,Style不能標記x:key-->  
        <Style TargetType="{x:Type TextBox}">  
            <Setter Property="Template">  
                <Setter.Value>  
                    <!--使用TemplateBinding,與模版目標一致-->  
                    <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}。運行效果以下圖:
htm

2.2 應用2對象

    把DataTemplate應用到某個數據類型上是設置DataTemplate的DataType屬性,而且DataTemplate做爲資源時也不能帶x:key標記, 例以下面的代碼:blog

<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:key-->  
        <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:事件

/// <summary>  
/// DataType  
/// </summary>  
public class Unit  
{  
    public int Price { get; set; }  
    public string Year { get; set; }  
}  

指定數據源:

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的效果相同:

<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>  
        <!--Xml中的元素名能夠做爲DataType-->  
        <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>  
        <!--XPath指定一組節點-->  
        <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>  
        <!--XmlDataProvider使用Binding-->  
        <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數據。

<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>  

事件處理器:

private void StackPanel_Click(object sender, RoutedEventArgs e)  
{  
    // Head爲XmlElement  
    XmlElement xmlElem = (e.OriginalSource as MenuItem).Header as XmlElement;  
    MessageBox.Show(xmlElem.Attributes["Name"].Value);  
}  

 

 

原文地址:http://www.javashuo.com/article/p-ghvukxai-gu.html

相關文章
相關標籤/搜索