1. 程式人生 > 其它 >WPF進階技巧和實戰05-樣式與行為

WPF進階技巧和實戰05-樣式與行為

樣式(style)是組織和重用格式化選項的重要工具。建立一系列封裝某些細節的樣式,然後通過屬性來應用樣式。

行為(behavior)是一款重用使用者介面程式碼更有挑戰性的工具。基本思想是:使用行為封裝一些通用的UI功能。如果具有適當的行為,可使用一兩行XAML標記將其附加到任何元素。

樣式基礎

樣式就是可應用於元素的屬性值集合。樣式支援觸發器,當屬性發生變化時,可通過觸發器改變控制元件的樣式。

樣式有5個重要屬性:

屬性 說明
Setters 設定屬性值,自動關聯事件處理程式的Setter物件或者EventSetter物件的集合
Triggers 繼承自TriggerBase類,並能自動改變樣式設定的物件集合。例如,當另一個屬性改變時,或者當發生某個事件時,可以修改樣式
Resources 希望用於樣式的資源集合。例如,可能需要使用一個物件設定多個屬性。這時,更高效 的做法是作為資源建立物件,然後再Setter物件中使用該資源(而不是使用巢狀的標籤為每一個Setter物件的一部分建立物件)
BasedOn 通過該屬性可建立繼承自(並且可以選擇地進行重寫)其他樣式設定的更具體形式
TargetType 該屬性標識應用樣式的元素型別。通過該屬性可建立隻影響特定型別元素的設定器,還可以建立能夠為恰當的元素型別自動起作用的設定器
<Style x:Key="TextBlockBaseStyle" TargetType="{x:Type TextBlock}">
  <Setter Property="TextWrapping" Value="NoWrap" />
  <Setter Property="TextTrimming" Value="None" />
  <Setter Property="VerticalAlignment" Value="Center" />
  <Setter Property="HorizontalAlignment" Value="Center" />
  <Setter Property="Width" Value="Auto" />
  <Setter Property="Height" Value="Auto" />
</Style>

觸發器

使用觸發器,可以自動完成簡單的樣式改變,例如,當屬性發生改變時進行相應,並自動調整樣式。觸發器通過Style.Triggers集合連結到樣式。每個樣式都可以有任意多個觸發器,而且每個觸發器都是TriggerBse的派生類例項。

名稱 說明
Trigger 最簡單的觸發器,可以監測依賴項屬性的變化,然後使用設定器改變樣式
MutiTrigger 和Trigger類似,但是觸發器聯合了多個條件。只有滿足所有條件,才會啟動觸發器
DataTrigger 這種觸發器使用資料繫結,與Trigger類似,只不過監測是任意繫結資料的變化
MultiDataTrigger 聯合多個數據觸發器
EventTrigger 最複雜的觸發器,當事件發生時,這種觸發器應用動畫

簡單觸發器

每個簡單的觸發器都指定了正在監視的屬性,以及正在等待的屬性值。觸發器的優點是不需要為翻轉他們而編寫任何邏輯。只要停止觸發器(條件不滿足時),元素就會恢復到之前的屬性值。

<Style.Triggers>
  <Trigger Property="IsMouseOver" Value="True">
    <Setter Property="Opacity" Value=".9" />
  </Trigger>
  <Trigger Property="IsPressed" Value="True">
    <Setter Property="Opacity" Value=".6" />
  </Trigger>
  <Trigger Property="IsEnabled" Value="False">
    <Setter Property="Opacity" Value="0.4" />
  </Trigger>
</Style.Triggers>

觸發器的順序決定了哪個觸發器最終生效,最後的觸發器會生效。

如果希望建立只有當幾個條件都成立時才啟用的觸發器,就可以使用MutiTrigger。這種觸發器提供了一個Conditions集合,可通過該集合定一系列觸發條件,這些條件不分先後順序,只有全部滿足時,觸發器才會工作。

事件觸發器

普通觸發器等待屬性發生變化,而事件觸發器等待特定的事件被觸發。事件觸發器要求使用者提供一系列修改控制元件的動作,這些動作通常被用作動畫。

行為

基本思想:建立封裝了一些通用使用者介面功能的行為。這一功能可以是基本功能(如啟動故事板或導航到超連結),也可以是複雜功能(如處理多點觸控互動,或構建使用實時物理引擎的碰撞模型)。一旦構建功能,就可將他們新增到任意應用程式的另一個控制元件中,具體方法是將該控制元件連結到適當的行為並設定行為的屬性。

using Microsoft.Xaml.Behaviors;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Course04
{
  public class DragInCanvasBehavior : Behavior<UIElement>
  {
    protected override void OnAttached()
    {
      base.OnAttached();
     
      this.AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown;
      this.AssociatedObject.MouseMove += AssociatedObject_MouseMove;
      this.AssociatedObject.MouseLeftButtonUp += AssociatedObject_MouseLeftButtonUp;
    }
    protected override void OnDetaching()
    {
      base.OnDetaching();
      this.AssociatedObject.MouseLeftButtonDown -= AssociatedObject_MouseLeftButtonDown;
      this.AssociatedObject.MouseMove -= AssociatedObject_MouseMove;
      this.AssociatedObject.MouseLeftButtonUp -= AssociatedObject_MouseLeftButtonUp;
    }

    Canvas canvas = null;
    bool isDragging = false;
    Point mouseOffset;
    private void AssociatedObject_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
      if(isDragging)
      {
        this.AssociatedObject.ReleaseMouseCapture();
        isDragging = false;
      }
    }
    private void AssociatedObject_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
    {
      if(isDragging)
      {
        Point point = e.GetPosition(canvas);
        this.AssociatedObject.SetValue(Canvas.LeftProperty, point.X - mouseOffset.X);
        this.AssociatedObject.SetValue(Canvas.TopProperty, point.Y - mouseOffset.Y);
      }
    }
    private void AssociatedObject_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
      if(canvas == null)
      {
        canvas = (Canvas)VisualTreeHelper.GetParent(this.AssociatedObject);
      }
      isDragging = true;
      mouseOffset = e.GetPosition(this.AssociatedObject);
      this.AssociatedObject.CaptureMouse();
    }
   
  }
}

XAML程式碼:

<Window
  x:Class="Course04.MainWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:local="clr-namespace:Course04"
  Title="MainWindow"
  Width="800"
  Height="450"
  mc:Ignorable="d">
  <Grid>
    <MediaElement LoadedBehavior="Play" Source="Normal.wav" Visibility="Collapsed" />
    <Canvas>
      <Rectangle Canvas.Left="60" Canvas.Top="20" Width="40" Height="50" Fill="Red" />
      <Ellipse Canvas.Left="80" Canvas.Top="100" Width="80" Height="50" Fill="Green">
        <b:Interaction.Behaviors>
          <local:DragInCanvasBehavior />
        </b:Interaction.Behaviors>
      </Ellipse>
      <Rectangle Canvas.Left="70" Canvas.Top="200" Width="40" Height="50" Fill="Yellow" />
    </Canvas>
  </Grid>
</Window>