介紹
在講解到樣式的時候我們說,樣式是爲了一系列元素共享一些屬性而存在的,歸根結底是爲了複用代碼和邏輯,而我們學習了觸發器之後,發現我們可以用觸發器寫一些簡單的邏輯到樣式中,但是這種簡單的邏輯有時候遠遠不夠。
當我們要實現一堆元素支持在Cancas上面拖放,停靠,縮放等功能的時候,觸發器就顯得不是那麼夠用了。
我們在複用代碼的時候,有下面三種方法,他們互相補充,構建了WPF的屬性重用架構,在合適的場景下選擇合適的方法可以極大的簡化我們的開發工作
- 樣式,主要是屬性的設置,用觸發器寫的簡單的控件行爲
- 自定義控件,爲了滿足某一功能編寫的可以公用的專職控件
- 行爲,封裝了一些通用的用戶界面功能的行爲,可以是十分複雜的功能的集合,一旦創建成功,可以將這種構建好的行爲用於任意一個其他控件中,十分的強大
依賴
行爲的必須依賴 System.Windows.Interactivity,我們在使用的時候可以從網上下載後,添加打項目中,通過引用該dll,引入對於System.Windows.Interactivity的依賴。這一步也是必須的
編寫行爲
我們通過一個例子,直觀的看一下行爲能夠做什麼,爲什麼它比觸發器更加的強大
我們就編寫之前提到過的,我們要通過寫一個行爲,讓一些原本很普通的控件具備在Canvas上被拖動的能力,行爲的編寫如下
public class DragInCanvasBehavior : Behavior<UIElement>
{
private Canvas canvas;
private bool isDragging = false;
private Point mouseOffset;
protected override void OnAttached()
{
base.OnAttached();
// 綁定事件處理
this.AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown;
this.AssociatedObject.MouseMove += AssociatedObject_MouseMove;
this.AssociatedObject.MouseLeftButtonUp += AssociatedObject_MouseLeftButtonUp;
}
private void AssociatedObject_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (isDragging)
{
// 釋放鼠標捕獲
AssociatedObject.ReleaseMouseCapture();
isDragging = false;
}
}
private void AssociatedObject_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (isDragging)
{
// 獲取控件在canvas上的位置
Point point = e.GetPosition(canvas);
// 移動鼠標的時候確定元素的新位置
AssociatedObject.SetValue(Canvas.TopProperty, point.Y - mouseOffset.Y);
AssociatedObject.SetValue(Canvas.LeftProperty, point.X - mouseOffset.X);
}
}
private void AssociatedObject_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// 如果canvas不存在,查找canvas
if (canvas == null)
{
canvas = (Canvas)VisualTreeHelper.GetParent(this.AssociatedObject);
}
//開始拖動
isDragging = true;
// 獲取鼠標點擊控件開始拖動的起始位置
mouseOffset = e.GetPosition(AssociatedObject);
// 使得我們要拖動的元素持續的獲取MouseMove事件
AssociatedObject.CaptureMouse();
}
protected override void OnDetaching()
{
base.OnDetaching();
// 移除事件處理
this.AssociatedObject.MouseLeftButtonDown -= AssociatedObject_MouseLeftButtonDown;
this.AssociatedObject.MouseMove -= AssociatedObject_MouseMove;
this.AssociatedObject.MouseLeftButtonUp -= AssociatedObject_MouseLeftButtonUp;
}
}
需要注意:
- 要使用行爲,必須依賴 System.Windows.Interactivity
- 我們一般都是要複寫 OnAttach 和 OnDetaching 兩個方法,用於在組件關聯以及解除關聯的時候,進行事件的監聽和移除監聽
- 監聽了我們感興趣的事件之後,就可以在事件的處理方法之中寫上控件的行爲
寫出了行爲之後,我們需要將行爲附加到元素上去,使用下面的方法
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d" Unloaded="Window_Unloaded"
Title="MainWindow" Height="450" Width="800">
<Canvas>
<Rectangle Canvas.Left="10" Canvas.Top="10" Fill="Yellow" Width="40" Height="60"></Rectangle>
<Ellipse Canvas.Left="10" Canvas.Top="70" Fill="Blue" Width="80" Height="60">
<i:Interaction.Behaviors>
<local:DragInCanvasBehavior></local:DragInCanvasBehavior>
</i:Interaction.Behaviors>
</Ellipse>
</Canvas>
</Window>
需要注意的是:
- xaml中同樣需要引入 Interactivity
- 只需要簡單的將行爲附加於控件,就實現了行爲中寫入的功能,十分的方便
Blend 支持
我們在編程的時候,如果使用Blend構建頁面,如果寫過一個行爲之後,可以在Blend的資產面板中找到這個行爲,直接拖放,就可以給一個元素添加我們新寫的行爲。