在Silverlight中自身並無提供拖放功能的相關實現,要實現拖放功能得藉助其事件支持(MouseLeftButtonDown、MouseLeftButtonUp和MouseMove)來完成,實際應用中咱們能夠經過行爲(Behavior)特性將拖放操做封裝爲行爲,這樣可達到代碼複用的效果。而在Blend中則直接提供了拖放操做行爲,它位於Microsoft.Expression.Interactions.dll的Microsoft.Expression.Interactivity.Layout名稱空間下。算法
Silverlight中的拖放操做一般是使用事件驅動動態定位對象的座標來實現,首先來看看如何經過代碼的可編程方式在Silverlight中實現拖放操做,以下代碼塊:編程
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;
MousePosition = e.GetPosition(null);
IsMouseCaptured = true;
element.CaptureMouse();
element.Cursor = Cursors.Hand;
}
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;
IsMouseCaptured = false;
element.ReleaseMouseCapture();
MousePosition.X = MousePosition.Y = 0;
element.Cursor = null;
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;
if (IsMouseCaptured)
{
double Y = e.GetPosition(null).Y - MousePosition.Y;
double X = e.GetPosition(null).X - MousePosition.X;
X = X + (double)element.GetValue(Canvas.LeftProperty);
Y = Y + (double)element.GetValue(Canvas.TopProperty);
element.SetValue(Canvas.LeftProperty, X);
element.SetValue(Canvas.TopProperty, Y);
MousePosition = e.GetPosition(null);
}
}
如上定義好的三個方法實現了對象的拖放算法,實際應用中只須要將須要進行拖放移動的對象分別添加MouseLeftButtonDown、MouseLeftButtonUp和MouseMove事件處理就好了。以下示例代碼:框架
attachedElement.MouseLeftButtonDown += (s, e) => OnMouseLeftButtonDown(s, e);
attachedElement.MouseLeftButtonUp += (s, e) => OnMouseLeftButtonUp(s, e);
attachedElement.MouseMove += (s, e) => OnMouseMove(s, e);
按照常規作法咱們會將以上相關方法的實現封裝爲一個基類以達到複用的目的,但本文不推薦使用基類去封裝拖放行爲,由於Silverlight有專門用於處理對象行爲的特性-Behaviors。在Silverlight中System.Windows.Interactivity命名空間下提供了行爲的基礎框架,咱們能夠進行自由的擴展行爲以實現本身的不一樣需求。安裝Blend後能夠在安裝目錄下找到Microsoft.Expression.Interactivity.dll這個庫,這個庫提供了一些比較經常使用的集中行爲擴展,在Blend中經過「窗口」--「資產」打開資產面板,選擇行爲資產就能夠查看到Silverlight 3中所提供的擴展行爲,以下圖: ide
咱們能夠將上面實現對象拖放的功能封裝爲行爲以達到代碼複用,在Blend中經過「文件」--「新建」菜單項可打開新建對象對話框。函數
Blend新建嚮導建立的行爲提供了一套行爲模板,以下代碼塊:測試
public class Behavior1 : Behavior<DependencyObject>
{
public Behavior1()
{
// 在此點下面插入建立對象所需的代碼。
//
// 下面的代碼行用於在命令
// 與要調用的函數之間創建關係。若是您選擇
// 使用 MyFunction 和 MyCommand 的已註釋掉的版本,而不是建立本身的實現,
// 請取消註釋如下行並添加對 Microsoft.Expression.Interactions 的引用。
//
// 文檔將向您提供簡單命令實現的示例,
// 您可使用該示例,而不是使用 ActionCommand 並引用 Interactions 程序集。
//
//this.MyCommand = new ActionCommand(this.MyFunction);
}
protected override void OnAttached()
{
base.OnAttached();
// 插入要在將 Behavior 附加到對象時運行的代碼。
}
protected override void OnDetaching()
{
base.OnDetaching();
// 插入要在從對象中刪除 Behavior 時運行的代碼。
}
/*
public ICommand MyCommand
{
get;
private set;
}
private void MyFunction()
{
// 插入要在從對象中刪除 Behavior 時運行的代碼。
}
*/
}
要實現自定義行爲經過此行爲模板進行自我擴展就好了,位於System.Windows.Interactivity中的Behavior提供了將行爲或命令進行封裝以達到可進行附加到其餘的一個對象上,須要注意的是自定義行爲默認繼承Behavior<DependencyObject>,使用DependencyObject類型的行爲是不能訪問對象的鼠標事件的,若是要訪問鼠標操做的事件,可使用具體的UI組件類型或者直接使用UI元素基類UIElement。this
下面爲將本篇前面實現對象拖放功能的代碼進行了行爲的封裝,完整代碼以下:編碼
/// <summary>
/// Behavior:封裝行爲和命令,便於附加到對象中。
/// DependencyObject:不能實現訪問鼠操做事件
/// UIElement:可訪問鼠標事件
/// </summary>
public class DragBehavior : Behavior<UIElement>
{
private UIElement attachedElement;
private UserControl parent;
private bool IsMouseCaptured;
private Point MousePosition;
protected override void OnAttached()
{
attachedElement = this.AssociatedObject;
parent = Application.Current.RootVisual as UserControl;
attachedElement.MouseLeftButtonDown += (s, e) => OnMouseLeftButtonDown(s, e);
attachedElement.MouseLeftButtonUp += (s, e) => OnMouseLeftButtonUp(s, e);
attachedElement.MouseMove += (s, e) => OnMouseMove(s, e);
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;
if (IsMouseCaptured)
{
double Y = e.GetPosition(null).Y - MousePosition.Y;
double X = e.GetPosition(null).X - MousePosition.X;
X = X + (double)element.GetValue(Canvas.LeftProperty);
Y = Y + (double)element.GetValue(Canvas.TopProperty);
element.SetValue(Canvas.LeftProperty, X);
element.SetValue(Canvas.TopProperty, Y);
MousePosition = e.GetPosition(null);
}
}
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;
IsMouseCaptured = false;
element.ReleaseMouseCapture();
MousePosition.X = MousePosition.Y = 0;
element.Cursor = null;
}
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;
MousePosition = e.GetPosition(null);
IsMouseCaptured = true;
element.CaptureMouse();
element.Cursor = Cursors.Hand;
}
protected override void OnDetaching()
{
base.OnDetaching();
}
}
經過行爲特性將對象的拖放功能進行封裝以達到複用的目的,以上就所有實現了這個功能,測試可經過Ctrol+Shift+B編譯項目,而後經過「資產」面板就能夠發現以上自定義擴展的拖放行爲。spa
使用行爲很是簡單,打開Blend的資源面板中,選中須要使用的行爲,將其拖放到要使用該行爲的對象(Blend中設計的界面對象)上就好了。其實在Blend也提供了拖放行爲:MouseDragElementBehavior,直接使用這個行爲和本篇所介紹的實現達到的是一樣的效果。如下爲分別使用這兩種行爲所對應生成的XAML編碼:設計
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:local="clr-namespace:DragBehavior"
xmlns:il="clr-namespace:Microsoft.Expression.Interactivity.Layout;assembly=Microsoft.Expression.Interactions"
x:Class="DragBehavior.MainControl"
Width="800" Height="600">
<Canvas x:Name="LayoutRoot" Background="White">
<Rectangle Fill="#FFFF0000" Stroke="#FF000000" Height="100" Width="100" Canvas.Left="100" Canvas.Top="100">
<i:Interaction.Behaviors>
<il:MouseDragElementBehavior/>
</i:Interaction.Behaviors>
</Rectangle>
<Ellipse Fill="#FF0000FF" Stroke="#FF000000" Height="100" Width="100" Canvas.Top="219" Canvas.Left="397">
<i:Interaction.Behaviors>
<local:DragBehavior/>
</i:Interaction.Behaviors>
</Ellipse>
</Canvas>
</UserControl>