《深入淺出WPF》筆記——模板篇


我們通常說的模板是用來參照的,同樣在WPF中,模板是用來作為制作控件的參照。

一、認識模板

1.1WPF菜鳥看模板

  前面的記錄有提過,控件主要是算法和數據的載體。控件的算法主要體現在可以激發的事件、可以調用的方法、能進行的操作等方面;控件的數據體現為:控件能展示哪些數據。上面兩方面終決定了控件,在以前的GUI界面上面,或者是Winform上面,控件的數據和功能耦合的太緊密,如果控件想以不同格式顯示數據的話,由於控件的形狀基本上都固定了,只有重新去自定義控件,以適合數據的顯示格式。在WPF中,就可以讓模板出馬了,如果你讓數據以不同的格式顯示,那么直接在數據的外衣——DataTemplate里面定義一些控件,安排好布局,到用的時間,直接給擁有數據的控件穿上衣服,數據控件上面就會參照着我們的模板來顯示數據了。當然還有一種情況,我們想讓一種控件的顯示稍作一點修改,由於傳統的控件的主要問題就是耦合性太強,才不易控制,在WPF中,一個控件,可能是多個控件的合體,這樣我們就相對更容易控制它。由於控件可以拆分,那么在控件里面添加一個控件或者是對某些控件的屬性做些修改,就不需要重新定義控件,只需要定義一個ControlTemlate,然后讓其裝在Style里面,最后讓控件擁有Style——那么控件就會照着ControlTemplate里面的定義來顯示。

1.2容易弄亂的幾個單詞區分

  由於模板系列的單詞很相像,很容易弄亂掉,所以我覺得還是很有必要把幾個單詞做簡要的說明。在區分之前,還是先了解一下Style,因為Style與ControlTemplate的聯系比較緊密,為了防止思路死鎖,在此稍作說明,具體的用法會在后面詳細記錄。Style是風格,對於一個風格,為了不至於有的控件使用該風格搞成四不像,如你讓濤哥天天穿個背心去開會,那還得了,一定是要穿的庄重吧,同樣控件也是如此,要定義風格要有適合的類,也即要定義其目標類型,然后根據目標的屬性來定義風格的具體內容。下面給出一個簡要的風格定義:

<Style x:Key="RoundCornerTextBoxStyle" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" 
                          Background
="{TemplateBinding Background}" CornerRadius="10" SnapsToDevicePixels="true"> <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style>

  接着解釋一下上面風格的含義:一個風格如果作為資源可以供多個控件使用的話,就可以使用x:key,BaseOn獲取或設置為當前樣式的基類型中定義的樣式,基類型中有定義,目標類型沒有定義的話,會使用基類型的樣式。TargetType是目標類型,對於簡單的Setter可以直接寫成<Setter Property="屬性值" Value=“對應的屬性值”/>對於復雜的可以通過內容標簽的寫法如: <Setter Property="BorderBrush" Value="Red"/>就是設置筆刷屬性為紅色,上面的代碼中是設置控件的Template屬性,為ControlTemplate類型的值,其中TemplateBinding為綁定目標控件的屬性,可以說TemplateBinding是控件專用的,其他和Binding保持一致。

稍微了解了Style之后再來看DataTemplate和ControlTemplate,他們是控件屬性的類型。具體的如下:

ControlTemplate類的代表:

  • ContentControl類型的Template屬性,例如Button為ContentControl類
  • ItemsControl類型的Template屬性,例如ListBox為ItemsControl類

關於兩種類型的元素具體可以參考控件和布局的記錄。

 

DataTemplate的典型代表:

  • ContentControl類型的ContentTemplate屬性
  • ItemsControl類型的ItemTemplate屬性
  • Gridview的行中的CellTemplate屬性

是不是有點亂了,下面給出一個草圖(圖1)來表述一下,下面的例子中可能會遇到很多類型名和屬性容易混淆的地方,可以回頭看一下。

 

圖1

二、數據的外衣DataTemplate

  在實際的UI設計中,可能會經常遇到,把已知的數據,通過一定的格式或者是按照一定的排列顯示出來,DataTemplate正是解決這樣的問題的模板,然后直接把DataTemplate利用空間的屬性穿在身上了,最終控件中的數據就會按照一定的排列顯示了,最終上了舞台。下面就通過實例來演示一下DataTemplate,該實例涉及到的內容可能比較多,主要包含綁定、資源、ItemsControl、Converter等的使用,如果不懂的話可以留言給我,好了,先看一下效果如圖2:

圖2

左邊的是一個UserControl(繼承與ContentControl),中間的是ListBox(繼承與ItemsControl)。當點擊ListBox的項時,可以改變左邊的顏色。直接上代碼了:

<Window x:Class="Chapter_09.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Chapter_09"
        Title="MainWindow" Height="350" Width="450">
    <Window.Resources>
        <local:NoConvertImage x:Key="nci"/>
        <!--定義詳細模板-->
        <DataTemplate x:Key="studentDetail">
            <Border BorderBrush="Black" BorderThickness="1" CornerRadius="6">
                <StackPanel Margin="5" Orientation="Vertical">
                    <Image  Source="{Binding No,Converter={StaticResource nci}}" Width="250"/>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="Name:" FontWeight="Bold" ></TextBlock>
                        <TextBlock Text="{Binding Name}"></TextBlock>
                        <TextBlock Text="Gender:" FontWeight="Bold" ></TextBlock>
                        <TextBlock Text="{Binding Sex}"></TextBlock>
                        <TextBlock Text="Age:" FontWeight="Bold" ></TextBlock>
                        <TextBlock Text="{Binding Age}"></TextBlock>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="No:" FontWeight="Bold" ></TextBlock>
                        <TextBlock Text="{Binding No}"></TextBlock>
                        <TextBlock Text="Color:" FontWeight="Bold" ></TextBlock>
                        <TextBlock Text="{Binding Color}"></TextBlock>
                    </StackPanel>
                    </StackPanel>
            </Border>
        </DataTemplate>
        <!--定義列表模板-->
        <DataTemplate x:Key="studentList">
            <Grid Margin="2">
                <StackPanel Orientation="Horizontal">
                    <Image Source="Resources/Images/月餅.png" />
                    <StackPanel>
                        <TextBlock Text="{Binding Name}"></TextBlock>
                        <TextBlock Text="{Binding Color}"></TextBlock>
                    </StackPanel>
                </StackPanel>
            </Grid>
        </DataTemplate>
    </Window.Resources>
    <StackPanel Orientation="Horizontal" >
        <UserControl ContentTemplate ="{StaticResource studentDetail}" Content="{Binding SelectedItem,ElementName=listBox}"/>
        <ListBox x:Name="listBox"  ItemTemplate="{StaticResource studentList}"/>
    </StackPanel>
</Window>

 

后台代碼

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Chapter_09
{
    /// <summary>
    /// MainWindow.xaml 的交互邏輯
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            //綁定ListBox和listViewItem
            InitialStudentList();
        }
        private void InitialStudentList()
        {
            List <Student> studentList= new List<Student>()
            {
                new Student(){Name="張飛",Age=53,Color="藍色",No="1",Sex=""},
                new Student(){Name="貂蟬",Age=53,Color="綠色",No="2",Sex=""},
                new Student(){Name="曹操",Age=53,Color="紅色",No="3",Sex=""},
                new Student(){Name="華佗",Age=53,Color="橙色",No="4",Sex=""},
                new Student(){Name="趙雲",Age=53,Color="紫色",No="5",Sex=""}
            };
            this.listBox.ItemsSource = studentList;         
        }
    }

    #region Student——學生類
    public class Student
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string No { get; set; }
        public string Sex { get; set; }
        public string Color { get; set; }
    }
    #endregion

    #region 把ID轉化成Uri形式
    public class NoConvertImage : IValueConverter
    {
        #region IValueConverter 成員

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string uriImg = string.Format(@"/Resources/Images/{0}.png", (string)value);
            return new BitmapImage(new Uri(uriImg, UriKind.Relative));
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    } 
    #endregion
}

  相對來說,后台代碼都是用的以前的知識,前台XAML代碼有幾點要記錄一下:在此處Datatemplate聲明為資源,然后通過ContentTemplate,ItemTemplate屬性獲取到資源。在上面的例子中還有要注意的地方是:UserControl的Content="{Binding SelectedItem,ElementName=listBox}屬性為Object類,所以在此綁定ListBox的選定項作為Content,在通過綁定來獲取圖片和人物的信息,除此還有一個要注意的,還有個是數據驅動,以前我們使用事件驅動應該是通過選項的id來得到Student實體,然后把實體的信息在詳情中顯示,經過的步驟比較多,可見數據驅動的好處。

 三、控件的外衣——ControlTemplate

   ControlTemplate主要用於改變控件的形狀,是對控件已有的形狀不滿意,通常借助Style來指定目標控件的Template屬性來實現。下面我們就來舉個例子,來以小見大。該例子是把TextBox的邊框改成圓角。本例子要用到Blend工具。

首先在新建的項目主窗體中添加一個TextBox,然后通過編輯模板->編輯副本(如圖3) 

 圖3

然后通過出現一個創建Style資源,選擇應用程序,以便其他控件也可以使用,如圖4。之后發現轉到App.xaml文件里面了。

圖4

  我們暫且不去看代碼的意思,我們先看對象和時間線的截圖(圖5)模板下面有兩個控件,但是具有層次關系,這不是我們以前記錄的可視樹嗎?所以為控件指定ControlTemplate衣服,其實就是來修改可視樹上的元素。我們把Style部分的代碼改為上面介紹Style時引用的代碼:

圖5

        <Style x:Key="TextBoxStyle1" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
                           Background="{TemplateBinding Background}" CornerRadius="10" SnapsToDevicePixels="true"> <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style>

發現現在主窗體的textBox已經變成橢圓形的了。上面的代碼只是讓Border代替了原來的控件。然后去掉了Style的觸發器(后面會記錄到)。關於ControlTemplate,重在編輯里面的元素,以及元素的屬性。下面看一下效果:

圖6

 除了上面的兩個模板之外還有個是只和ItemsControl有關的PanelTemplate:指定 ItemsPresenterItemsControl 的項的布局創建的面板.也就是指定一個承載ItemsControl的條目的面板,以便使控件的布局更加靈活。例如,我們平時見到的ListBox控件都是豎着下來的,我們下面演示一個橫着排列的,其中就利用到了PanelTemplate。代碼和效果如圖7:

 圖7

此功能不是本記錄的重點,所以不做過多介紹。 

 四、DataTeplate的另外幾種用法

4.1設置DataTemplate的DataType屬性  

  除了為控件指定DataTeplate,還可以不指定DataTemplate。而是在DataTemplate設置DataType屬性,類似於 Style 類的 TargetType 屬性的屬性。 如果將此屬性設置為數據類型,但沒有指定 x:KeyDataTemplate 自動應用於該類型的數據對象 。下面的例子是自動的使用於ItemsControl的條目:

<Window x:Class="WpfControlTemlate.DataTypeOfDataTemplate"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfControlTemlate"
        xmlns:c="clr-namespace:System.Collections;assembly=mscorlib"
        Title="DataTypeOfDataTemplate" Height="300" Width="300">
    <Window.Resources>
        <!--會自動的根據數據類型來做適合控件的衣服-->
        <DataTemplate DataType="{x:Type local:Unit}">
            <Grid>
                <StackPanel Orientation="Horizontal">
                    <Grid>
                        <Rectangle Stroke="Yellow" Fill="Orange" Width="{Binding Price}"/>
                        <TextBlock Text="{Binding Year}"/>
                    </Grid>
                    <TextBlock Text="{Binding Price}"/>
                </StackPanel>
            </Grid>
        </DataTemplate>
        <c:ArrayList x:Key="ds">
            <local:Unit Year="2011年" Price="100"/>
            <local:Unit Year="2010年" Price="120"/>
            <local:Unit Year="2012年" Price="140"/>
            <local:Unit Year="2013年" Price="160"/>
            <local:Unit Year="2014年" Price="180"/>
        </c:ArrayList>
    </Window.Resources>
    <StackPanel>
        <ListBox ItemsSource="{StaticResource ds}"/>
        <ComboBox ItemsSource="{StaticResource ds}" Margin="5"/>
    </StackPanel>
</Window>

其中Unit的代碼為:

    public class Unit
    {
        public int Price { get; set; }
        public string Year { get; set; }
    }

效果如圖8:

圖8

4.2DataTemplate對XML的支持

  下面兩個例子為兩個比較常見的例子(TreeView和Menu),只給出代碼和效果圖,具體用的時間可以自己去試着修改:

XML
<?xml version="1.0" encoding="utf-8" ?>
<Data xmlns="">
  <Grade Name="一年級">
    <Class Name="甲班">
      <Group Name="A組"/>
      <Group Name="B組"/>
      <Group Name="C組"/>
    </Class>
    <Class Name="乙班">
      <Group Name="A組"/>
      <Group Name="B組"/>
      <Group Name="C組"/>
    </Class>
  </Grade>
  <Grade Name="二年級">
    <Class Name="甲班">
      <Group Name="A組"/>
      <Group Name="B組"/>
      <Group Name="C組"/>
    </Class>
    <Class Name="乙班">
      <Group Name="A組"/>
      <Group Name="B組"/>
      <Group Name="C組"/>
    </Class>
  </Grade>
  <Grade Name="三年級">
    <Class Name="甲班">
      <Group Name="A組"/>
      <Group Name="B組"/>
      <Group Name="C組"/>
    </Class>
    <Class Name="乙班">
      <Group Name="A組"/>
      <Group Name="B組"/>
      <Group Name="C組"/>
    </Class>
  </Grade>
</Data>
XAML
<Window x:Class="WpfControlTemlate.HierarchicalDataTemplate"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="HierarchicalDataTemplate" Height="300" Width="300">
    <Window.Resources>
        <XmlDataProvider x:Key="ds" Source="Data.xml" XPath="Data/Grade"/>
        <!--ItemsSource="{Binding XPath=Class}"表示下一個節點的源-->
        <HierarchicalDataTemplate DataType="Grade" ItemsSource="{Binding XPath=Class}">
            <TextBlock Text="{Binding XPath=@Name}"/>
        </HierarchicalDataTemplate>
        
        <HierarchicalDataTemplate DataType="Class" ItemsSource="{Binding XPath=Group}">
            <RadioButton Content="{Binding XPath=@Name}" GroupName="gn"/>
        </HierarchicalDataTemplate>
        
        <HierarchicalDataTemplate DataType="Group" >
            <CheckBox Content="{Binding XPath=@Name}" />
        </HierarchicalDataTemplate>
        
    </Window.Resources>
    <Grid>
        <TreeView Margin="5" ItemsSource="{Binding Source={StaticResource ds}}"/>
    </Grid>
</Window>

效果如圖9

圖9

XML
<?xml version="1.0" encoding="utf-8" ?>
<Data xmlns="">
  <Operation Name="文件" Gesture="F">
    <Operation Name="新建" Gesture="N">
      <Operation Name="項目" Gesture="Control+P"/>
      <Operation Name="網站" Gesture="Control+W"/>
      <Operation Name="文檔" Gesture="Control+D"/>
    </Operation>
    <Operation Name="保存" Gesture="S"/>
    <Operation Name="打印" Gesture="P"/>
    <Operation Name="退出" Gesture="X"/>
  </Operation>
  <Operation Name="編輯" Gresture="E">
      <Operation Name="拷貝" Gesture="Control+C"/>
      <Operation Name="剪切" Gesture="Control+X"/>
      <Operation Name="粘貼" Gesture="Control+V"/>
    </Operation>
</Data>
XMAL
<Window x:Class="WpfControlTemlate.MenuTemplate"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MenuTemplate" Height="300" Width="300">
    <Window.Resources>
        <XmlDataProvider x:Key="ds" Source="MenuList.xml" XPath="Data/Operation"/>

        <HierarchicalDataTemplate DataType="Operation" ItemsSource="{Binding XPath=Operation}">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding XPath=@Name}" Margin="10,0"/>
                <TextBlock Text="{Binding XPath=@Gesture}"/>
            </StackPanel>
        </HierarchicalDataTemplate>
    </Window.Resources>
    <StackPanel MenuItem.Click="StackPanel_Click">
        <Menu ItemsSource="{Binding Source={StaticResource ds}}"/>
    </StackPanel>
</Window>

后台代碼是添加了單擊事件來獲取點擊的是哪個菜單選項,我們可以根據其選項作出相應的操作。

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

效果如圖10

圖10

五、Style

5.1Style的Setter

  前面已經稍微理解了一下Style的概念,下面就來記錄一下其用法,Setter是設置器的意思。Style有個Setters標簽,里面的值為Setter集合。對應的格式為<Setter Property="屬性值" Value=“對應的屬性值”/>下面來看個例子:

圖11

 其中上面的Setters標簽可以省略。通過Style來限制TextBox的格式,如果不想使用的話,可以使用Style=“{x:Null}”。當然Style也可以添加在App.xaml文件中。如果想用style的話可以用<TextBox Text="Hello Style" Style="{DynamicResource textBoxStyle}"/>動態資源來套用。

 5.2  Style中的基本Trigger

   Trigger,觸發器,當某些條件滿足的時間會觸發一個行為。下面先介紹一下基本trigger。Trigger中也有Property和Value,用來限制條件,除此之外還有Setters,表示滿足條件呈現的樣式。下面的圖為當CheckBox選中是字體呈現Orange顏色和20號字體。

圖12

5.3 Style中的MultiTrigger

  這個觸發器不能從名字上面理解,該觸發器應該是多條件觸發器,是屬性滿足了條件呈現特點的Style。下面例子為CheckBox選中,且Content為123的顯示一定的Style。

圖13

5.4由數據觸發的DataTrigger

   在程序設計中,經常碰到如果客戶輸入不合法的字符串,要顯示文本框為紅色,來提醒客戶。下面就演示一下具體怎么用:下面的例子為TextBox中的Text長度小於7會讓Border保持紅色。

XAML
<Window x:Class="Style.DataTriggerOfStyle"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Style"
        Title="DataTriggerOfStyle" Height="300" Width="300">
    <Window.Resources>
        <local:LongToBoolConverter x:Key="LongToBool"/>
        <Style TargetType="TextBox">
            <Style.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={x:Static RelativeSource.Self},Path=Text.Length,Converter={StaticResource LongToBool}}" Value="false">
                    <Setter Property="BorderBrush" Value="Red"/>
                    <Setter Property="BorderThickness" Value="1"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <StackPanel>
        <TextBox Margin="5"/>
        <TextBox Margin="5"/>
        <TextBox Margin="5"/>
    </StackPanel>
</Window>
View Code
public class LongToBoolConverter : IValueConverter
    {
        #region IValueConverter 成員

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            int textLength = (int)value;
            return textLength>6?true:false;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

效果為圖14:

圖14

   上面的代碼中有個的地方是需要解釋一下,綁定中有個的RelativeSource,RelativeSource 通過指定綁定源相對於綁定目標的位置,獲取或設置綁定源。上面的意思其實就是綁定源的本身。上面還有個Converter,參數中的value已經是長度了,所以不需要直接轉化為int型就可以了。

 5.5多數據條件觸發的MultiDataTrigger

  和上面的MultiTrigger相比,MultiDataTrigger主要驗證數據,MultiTrigger驗證屬性。 

XAML
<Window x:Class="Style.MultiDataTriggerOfStyle"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MultiDataTriggerOfStyle" Height="300" Width="300">
    <Window.Resources>
        <Style TargetType="ListBoxItem">
            <Setter Property="ContentTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="{Binding ID}" Width="60"/>
                            <TextBlock Text="{Binding Name}" Width="120"/>
                            <TextBlock Text="{Binding Age}" Width="60"/>
                        </StackPanel>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding Path=ID}" Value="2"/>
                        <Condition Binding="{Binding Path=Name}" Value="Tom"/>
                    </MultiDataTrigger.Conditions>
                    <MultiDataTrigger.Setters>
                        <Setter Property="Background" Value="Orange"/>
                    </MultiDataTrigger.Setters>
                </MultiDataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <StackPanel>
        <ListBox x:Name="listBoxStudent" Margin="5"/>
    </StackPanel>
</Window>
cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace Style
{
    /// <summary>
    /// MultiDataTriggerOfStyle.xaml 的交互邏輯
    /// </summary>
    public partial class MultiDataTriggerOfStyle : Window
    {
        public MultiDataTriggerOfStyle()
        {
            InitializeComponent();
            this.listBoxStudent.ItemsSource = new List<Student> { new Student { ID = 1, Name = "Tim", Age = 30 }
                                                                , new Student { ID = 2, Name = "Tom", Age = 30 }
                                                                , new Student { ID = 3, Name = "lzp", Age = 30 }
                                                                , new Student { ID = 4, Name = "haiziguo", Age = 30 }};
        }
    }
    public class Student
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }
}

效果如圖15:

圖15

5.6事件觸發的EventTrigger

   該觸發器與其他觸發器不大一樣,他不是屬性也不是數據觸發Style改變的,而是由事件觸發的;被觸發后不是執行的Setter,而是執行的一段動畫。關於動畫不做說明,下面只給出實例。記錄完動畫的章節,再回來看看。下面的例子是鼠標移到Button控件和離開執行的動畫。

XAML
<Window x:Class="Style.EventTriggerOfStyle"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="EventTriggerOfStyle" Height="300" Width="300">
    <Window.Resources>
        <Style TargetType="Button">
            <Style.Triggers>
                <EventTrigger RoutedEvent="MouseEnter">
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation To="150" Duration="0:0:0:2" Storyboard.TargetProperty="Width"/>
                            <DoubleAnimation To="150" Duration="0:0:0:2" Storyboard.TargetProperty="Height"/>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
                <EventTrigger RoutedEvent="MouseLeave">
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation  Duration="0:0:0:2" Storyboard.TargetProperty="Width"/>
                            <DoubleAnimation  Duration="0:0:0:2" Storyboard.TargetProperty="Height"/>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="FrameworkElement.Loaded"/>
    </Window.Triggers>
    <Canvas>
        <Button Width="40" Height="40" Content="OK"/>
    </Canvas>
</Window>

 六、總結

  本篇記錄主要從DataTemplate和ControlTemplate入手,通過一些小例子來說明了他們的用途。注意區分其使用場合,前者只要是控制數據的顯示方式,后者是控制控件的已有形狀的改變。除此之外,還介紹了Style,由於其概念簡單性,沒有做過多的解釋,只是給出了幾個例子,等用到的時間再進行查閱。不足的地方是:關於ContentPresenter與DataTemplate以及ControlTemplate之間的關系不是太理解,所以本文少了一部分《尋找失落的控件》,如果有比較好的文章或者是比較好的資料幫助理解的,請留言,將不勝感激!本文是讀書筆記,里面難免有理解不對的地方,歡迎討論!最后祝大家節日愉快!下一篇:《深入淺出WPF》筆記——繪圖與動畫 。 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM