Silverlight & Blend动画设计系列八:拖放(Drag-Drop)操作与拖放行为(DragBehavior)

本文介绍如何在Silverlight中实现拖放功能,并通过行为(Behavior)特性封装这一功能,以便于代码复用。文中详细展示了如何使用MouseLeftButtonDown等事件实现拖放,并将其实现为可复用的行为。

  在Silverlight中自身并没有提供拖放功能的相关实现,要实现拖放功能得借助其事件支持(MouseLeftButtonDown、MouseLeftButtonUp和MouseMove)来完成,实际应用中我们可以通过行为(Behavior)特性将拖放操作封装为行为,这样可达到代码复用的效果。而在Blend中则直接提供了拖放操作行为,它位于Microsoft.Expression.Interactions.dll的Microsoft.Expression.Interactivity.Layout名称空间下。

  Silverlight中的拖放操作通常是使用事件驱动动态定位对象的坐标来实现,首先来看看如何通过代码的可编程方式在Silverlight中实现拖放操作,如下代码块:

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> private void OnMouseLeftButtonDown( object sender,MouseButtonEventArgse)
{
FrameworkElementelement
= sender as FrameworkElement;
MousePosition
= e.GetPosition( null );
IsMouseCaptured
= true ;
element.CaptureMouse();
element.Cursor
= Cursors.Hand;
}

private void OnMouseLeftButtonUp( object sender,MouseButtonEventArgse)
{
FrameworkElementelement
= sender as FrameworkElement;
IsMouseCaptured
= false ;
element.ReleaseMouseCapture();
MousePosition.X
= MousePosition.Y = 0 ;
element.Cursor
= null ;
}

private void OnMouseMove( object sender,MouseEventArgse)
{
FrameworkElementelement
= 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事件处理就行了。如下示例代码:

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> 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中所提供的扩展行为,如下图: 

        

  我们可以将上面实现对象拖放的功能封装为行为以达到代码复用,在Blend中通过“文件”--“新建”菜单项可打开新建对象对话框。

        

  Blend新建向导创建的行为提供了一套行为模板,如下代码块:

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> public class Behavior1:Behavior < DependencyObject >
{
public Behavior1()
{
// 在此点下面插入创建对象所需的代码。

//
// 下面的代码行用于在命令
// 与要调用的函数之间建立关系。如果您选择
// 使用MyFunction和MyCommand的已注释掉的版本,而不是创建自己的实现,
// 请取消注释以下行并添加对Microsoft.Expression.Interactions的引用。
//
// 文档将向您提供简单命令实现的示例,
// 您可以使用该示例,而不是使用ActionCommand并引用Interactions程序集。
//
// this.MyCommand=newActionCommand(this.MyFunction);
}

protected override void OnAttached()
{
base .OnAttached();

// 插入要在将Behavior附加到对象时运行的代码。
}

protected override void OnDetaching()
{
base .OnDetaching();

// 插入要在从对象中删除Behavior时运行的代码。
}

/*
publicICommandMyCommand
{
get;
privateset;
}

privatevoidMyFunction()
{
//插入要在从对象中删除Behavior时运行的代码。
}
*/
}

  要实现自定义行为通过此行为模板进行自我扩展就行了,位于System.Windows.Interactivity中的Behavior提供了将行为或命令进行封装以达到可进行附加到其他的一个对象上,需要注意的是自定义行为默认继承Behavior<DependencyObject>,使用DependencyObject类型的行为是不能访问对象的鼠标事件的,如果要访问鼠标操作的事件,可以使用具体的UI组件类型或者直接使用UI元素基类UIElement。

  下面为将本篇前面实现对象拖放功能的代码进行了行为的封装,完整代码如下:

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> /// <summary>
/// Behavior:封装行为和命令,便于附加到对象中。
/// DependencyObject:不能实现访问鼠操作事件
/// UIElement:可访问鼠标事件
/// </summary>
public class DragBehavior:Behavior < UIElement >
{
private UIElementattachedElement;
private UserControlparent;
private bool IsMouseCaptured;
private PointMousePosition;

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,MouseEventArgse)
{
FrameworkElementelement
= 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,MouseButtonEventArgse)
{
FrameworkElementelement
= sender as FrameworkElement;
IsMouseCaptured
= false ;
element.ReleaseMouseCapture();
MousePosition.X
= MousePosition.Y = 0 ;
element.Cursor
= null ;
}

private void OnMouseLeftButtonDown( object sender,MouseButtonEventArgse)
{
FrameworkElementelement
= sender as FrameworkElement;
MousePosition
= e.GetPosition( null );
IsMouseCaptured
= true ;
element.CaptureMouse();
element.Cursor
= Cursors.Hand;
}

protected override void OnDetaching()
{
base .OnDetaching();
}
}

  通过行为特性将对象的拖放功能进行封装以达到复用的目的,以上就全部实现了这个功能,测试可通过Ctrol+Shift+B编译项目,然后通过“资产”面板就可以发现以上自定义扩展的拖放行为。

        

  使用行为非常简单,打开Blend的资源面板中,选中需要使用的行为,将其拖放到要使用该行为的对象(Blend中设计的界面对象)上就行了。其实在Blend也提供了拖放行为:MouseDragElementBehavior,直接使用这个行为和本篇所介绍的实现达到的是同样的效果。以下为分别使用这两种行为所对应生成的XAML编码:

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> < 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 >

  推荐资源:

  Expression Blend实例中文教程(9) - 行为快速入门Behaviors

  Silverlight中实现强壮的、可复用的拖放行为

  Silverlight & Blend动画设计系列文章

  MSDN:http://msdn.microsoft.com/zh-cn/library/cc189090(VS.95).aspx

  http://www.silverlight.net/learn/quickstarts/animations/

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值