行為的目的在於封裝部分UI功能,那樣就可以直接應用於元素而不用寫任何代碼。行為是一組相關操作的組合,它包含了觸發器(監聽某個事件或改變)和動作(完成適當的操作)的工作。例如,Deep Zoom功能由一些事件處理常式組成,允許通過滑鼠按鍵和滑鼠滾輪對Deep Zoom 映像進行平移和縮放。
想象一下在Canvas上如何讓一個元素可以擁有拖放的行為,首先要建立一個派生自Behavior的類,Behavior是個泛型類,可以通過型別參數將行為限制到特定的元素,通常可以使用UIElement 或者是 FrameworkElement。
當使用者按下滑鼠左鍵,DragInCanvasBehavior開始拖拽操作,記錄下元素左上方與滑鼠指標之間的位移量,並捕獲滑鼠。
public class DragInCanvasBehavior : Behavior<UIElement> { protected override void OnAttached() { base.OnAttached(); //附加事件處理常式 this.AssociatedObject.MouseLeftButtonDown += new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown); this.AssociatedObject.MouseMove += new MouseEventHandler(AssociatedObject_MouseMove); this.AssociatedObject.MouseLeftButtonUp += new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonUp); } protected override void OnDetaching() { base.OnDetaching(); //分離事件處理常式 this.AssociatedObject.MouseLeftButtonDown -= new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown); this.AssociatedObject.MouseMove -= new MouseEventHandler(AssociatedObject_MouseMove); this.AssociatedObject.MouseLeftButtonUp -= new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonUp); } //記錄當前元素所放置的Canvas private Canvas canvas; //記錄當前元素是否正被拖拽 private bool isDragging = false; //當滑鼠左鍵按下的時候,記錄單擊所在的準確位置 private Point mouseOffset; private void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { //找到Canvas if (canvas == null) { canvas = (Canvas)VisualTreeHelper.GetParent(this.AssociatedObject); } //拖拽模式開始 isDragging = true; //擷取按一下滑鼠時相對於元素的位置 //因此元素左上方的座標為(0, 0) mouseOffset = e.GetPosition(AssociatedObject); //捕獲滑鼠,這樣即使使用者突然將滑鼠指標拽到元素外,仍然可以接收到MouseMove事件 AssociatedObject.CaptureMouse(); } private void AssociatedObject_MouseMove(object sender, MouseEventArgs e) { if (isDragging) { //滑鼠指標相對於Canvas的位置 Point point = e.GetPosition(canvas); //重定位元素 Canvas.SetLeft(AssociatedObject, point.X - mouseOffset.X); Canvas.SetTop(AssociatedObject, point.Y - mouseOffset.Y); } } private void AssociatedObject_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { if (isDragging) { AssociatedObject.ReleaseMouseCapture(); isDragging = false; } } }
接下來只要簡單的附加到Canvas中的任何元素,就可以使用這個行為。
<UserControl x:Class="SilverlightApplication1.Behaviors.BehaviorSample" 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:custom="clr-namespace:SilverlightApplication1.Behaviors" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <Canvas> <Rectangle Canvas.Left="10" Canvas.Top="10" Width="40" Height="60" Fill="Yellow" /> <Ellipse Canvas.Left="10" Canvas.Top="70" Fill="Blue" Width="80" Height="60"> <i:Interaction.Behaviors> <custom:DragInCanvasBehavior /> </i:Interaction.Behaviors> </Ellipse> <Ellipse Canvas.Left="80" Canvas.Top="70" Fill="OrangeRed" Width="40" Height="70"> <i:Interaction.Behaviors> <custom:DragInCanvasBehavior /> </i:Interaction.Behaviors> </Ellipse> </Canvas></UserControl>