一步一步学Silverlight 2系列(5):实现简单的拖放功能

概述

Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, Ironpython,对JSON、Web Service、WCF以及Sockets的支持等一系列新的特性。《一步一步学Silverlight 2系列》文章带您快速进入Silverlight 2开发。

本文为系列文章第五篇,利用前面讲过的鼠标事件处理实现简单的拖放功能。

准备XAML

在实现拖放功能中,分为三个步骤:

1.按下鼠标,触发MouseLeftButtonDown事件,选择要拖动的对象。

2.移动鼠标,触发MouseMove事件,移动选择的对象。

3.放开鼠标,触发MouseLeftButtonUp事件,停止捕捉事件。

做一个简单的界面,用一个按钮来显示拖放,如下XAML声明:

<Canvas Background="#46461F">
    <Button 
       MouseLeftButtonDown="OnMouseDown" 
       MouseMove="OnMouseMove"
       MouseLeftButtonUp="OnMouseUp" 
       Canvas.Left="50" Canvas.Top="50" Background="Red"
       FontSize="18"
       Width="160" Height="80">
        <Button.Content>
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"
                        VerticalAlignment="Center">
                <Image Source="smile_6.png"></Image>
                <TextBlock Text="拖动我" VerticalAlignment="Center" Margin="10"></TextBlock>
            </StackPanel>
        </Button.Content>
    </Button>
</Canvas>

这里为了界面显示效果,使用了控件模板,后续会专门讲到。

开始拖放操作

开始拖放操作,实现MouseLeftButtonDown事件处理程序,用两个全局变量来记录当前鼠标的位置和鼠标是否保持移动。

bool trackingMouseMove = false;
Point mousePosition;

void OnMouseDown(object sender, MouseButtonEventArgs e)
{
    FrameworkElement element = sender as FrameworkElement;
    mousePosition = e.GetPosition(null);
    trackingMouseMove = true;
    if (null != element)
    {
        element.CaptureMouse();
        element.Cursor = Cursors.Hand;
    }
}

移动对象

移动对象,实现MouseMove事件处理程序,计算元素的位置并更新,同时更新鼠标的位置。

void OnMouseMove(object sender, MouseEventArgs e)
{
    FrameworkElement element = sender as FrameworkElement;
    if (trackingMouseMove)
    {
        double deltaV = e.GetPosition(null).Y - mousePosition.Y;
        double deltaH = e.GetPosition(null).X - mousePosition.X;
        double newTop = deltaV + (double)element.GetValue(Canvas.TopProperty);
        double newLeft = deltaH + (double)element.GetValue(Canvas.LeftProperty);

        element.SetValue(Canvas.TopProperty, newTop);
        element.SetValue(Canvas.LeftProperty, newLeft);

        mousePosition = e.GetPosition(null);
    }
}

完成拖放操作

完成拖放操作,实现MouseLeftButtonUp事件处理程序。

void OnMouseUp(object sender, MouseButtonEventArgs e)
{
    FrameworkElement element = sender as FrameworkElement;
    trackingMouseMove = false;
    element.ReleaseMouseCapture();

    mousePosition.X = mousePosition.Y = 0;
    element.Cursor = null;
}

效果显示

最终,完成后的效果如下

TerryLee_Silverlight2_0035

拖动按钮

TerryLee_Silverlight2_0036

结束语

本文实现了一个简单的拖放功能(示例来自于Silverlight 2 SDK),点击下载文本示例代码。

下一篇:一步一步学Silverlight 2系列(6):键盘事件处理

作者:TerryLee
出处:http://terrylee.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
Tag标签: Silverlight,XAML
posted @ 2008-03-08 00:40 TerryLee 阅读(13995) 评论(66)  编辑 收藏 网摘 所属分类: [03]  银光点亮世界

  回复  引用    
#1楼2008-03-08 23:34 | ohaiyo[未注册用户]
GetPosition(relativeTo)函数里的参数是表示位置是相对于relativeTo参数对象的

你上面的实例里GetPosition(null),这个怎样理解的?

  回复  引用    
#2楼2008-03-08 23:45 | ohaiyo[未注册用户]
明了
To specify the object relative to the overall  Silverlight coordinate system, set the relativeTo parameter to null.

  回复  引用  查看    
#3楼2008-03-20 00:28 | Cat Chen      
Silverlight2.0也没有内置拖放支持,这点让人比较失望……
  回复  引用  查看    
#4楼[楼主]2008-03-20 09:06 | TerryLee      
@Cat Chen
是啊,现在只能是靠鼠标事件来控制元素的位置实现拖放

  回复  引用  查看    
#5楼2008-04-25 13:47 | aito      
Silverlight 2 SDK 有没有中文的了?可不可以给个地址出来呢?
  回复  引用  查看    
#6楼2008-06-16 18:35 | 飄lá┽蕩去      
在beta2版本下不成功啊,应该怎么做啊?
  回复  引用  查看    
#7楼2008-06-17 22:55 | 房客      
冇错,在beta2中,好像这个实现不了。
  回复  引用  查看    
#8楼[楼主]2008-06-17 22:58 | TerryLee      
@房客
该系列文章的环境是Beta 1!

  回复  引用  查看    
#9楼2008-06-17 23:00 | 房客      
嗯。我知道,我只是说出你的例子在Beta2中可能出现的问题,让我们后来学习的人不要在beta2中死钻这个问题,我调了半天才发现的。

我调试了下,好像是在程序中不可以设置Canvas的属性。比如:
SetValue(Canvas.LeftProperty, 100);

  回复  引用  查看    
#10楼[楼主]2008-06-18 00:00 | TerryLee      
@房客
Beta 2中SetValue方法修改过了,不可以直接指定一个double类型的值,需要转换为Object对象才行。

  回复  引用  查看    
#12楼2008-06-20 15:59 | 飄lá┽蕩去      
使用了控件模板之后,事件怎么触发不了了???
  回复  引用    
#13楼2008-06-24 14:18 | allen.wang[未注册用户]
OnMouseDown和OnMouseUp在Beta2的环境下无法触发,不知道Beta1有没有这个问题?但OnMouseMove可以触发,非常奇怪!
  回复  引用    
#14楼2008-06-24 17:24 | cx19800421[未注册用户]
确实OnMouseDown和OnMouseUp在Beta2的环境下无法触发
  回复  引用    
#15楼2008-06-25 09:16 | botsing[未注册用户]
最近开始看这个系列的教程,我用的是beta2的,好像mousedown和mouseup在beta2中并不是完全不能用的,Button组件是不行的,不过我在一个IMAGE组件的这两个事件添加了这些代码之后,可以实现拖动的
难道这个跟控件类型有关?

  回复  引用  查看    
#16楼2008-06-25 22:53 | Goumh      
没错,在beta2中,Button 控件不能实现拖放操作,但是其它控件似乎可以,比TextBlock 、Image 等。
  回复  引用  查看    
#17楼[楼主]2008-06-26 09:56 | TerryLee      
@Goumh
不是不可以,是在事件处理机制上有些变化。。,有空我会详细解释一下。

  回复  引用  查看    
#18楼2008-06-26 19:27 | 阿胜      
貌似在BETA 2中,按钮没有MouseLeftButtonDown,和MouseLeftButtonUp事件吧。
  回复  引用    
#19楼2008-06-26 21:12 | botsing[未注册用户]
@阿胜
事件同样是存在的,只是添加了事件代码之后却不会被触发

等待楼主的讲解吧

  回复  引用  查看    
#20楼2008-06-27 20:38 | 阿胜      
@botsing
呵呵。是的。

  回复  引用    
#21楼2008-07-15 15:19 | garf[未注册用户]
能说一下这个网站中silverlight插件上边的那个拖动的实现思路吗
http://www.flowerskc.com/FlowersKC/WebPages/Weddings.aspx

  回复  引用  查看    
#22楼[楼主]2008-07-21 10:22 | TerryLee      
@garf
这个似乎也没有多少难的,主要在鼠标事件里面控制一下动画,可以在Silverlight.net网站上找到类似的例子。。。

  回复  引用    
#23楼2008-08-20 10:55 | xhz[未注册用户]
buttong在Beta2中不能拖动了,改成Image就可以拖动了
================================================
<UserControl....>
<Canvas Background="#46461F">
<Image Source="smile_6.png"
MouseLeftButtonDown="OnMouseDown"
MouseMove="OnMouseMove"
MouseLeftButtonUp="OnMouseUp"/>
</Canvas>
</UserControl>

  回复  引用    
#24楼2008-08-22 17:56 | ChMal[未注册用户]
beta2 中用Button的子控件StackPanel的MouseLeftButtonUp和MouseLeftButtonDown事件就可以实现了。因为控件的事件是向上传递的。
  回复  引用    
#25楼2008-08-22 18:01 | ChMal[未注册用户]
@TerryLee
Beta 2中SetValue方法修改过了,不可以直接指定一个double类型的值,需要转换为Object对象才行。
这个好像直接传递double值,也可以执行。

  回复  引用    
#26楼2008-08-26 18:50 | 卡索![未注册用户]
回各位好朋友!
在进行阅读楼主的博文时,在实际的操作中确实出现了在Beta2版本中Button无MouseLeftButtonDown和MouseLeftButtonUp这两个事件。
如果把Button换成StackPanel,博主的代码不用进行修改是可以执行成功的!
有遇到和我类似问题的朋友们可以尝试测试下!

  回复  引用    
#27楼2008-09-11 11:18 | Nick Lee[未注册用户]
把MouseLeftButtonDown和MouseLeftButtonUp这两个事件移到StackPanel下, 确实可以运行. 但是偶尔会无法触发事件而拖不动.要多按几下才又拖的动. 有人知道为何吗?

  回复  引用  查看    
#28楼[楼主]2008-09-17 00:58 | TerryLee      
@Nick Lee
可能是事件路由的问题。

  回复  引用    
#29楼2008-09-22 11:29 | snowblue[未注册用户]
@Nick Lee
因为StackPanel并不是平铺到整个Button控件上,只是紧凑包围了内容,你把鼠标点在内容上,如图片、文字,就可以执行事件了,如果点在Button的内容外面的空白区域,那些不是StackPanel的覆盖范围,则不执行事件

  回复  引用    
#30楼2008-10-05 21:04 | XiiL[未注册用户]
在Beta2中,Button(还有一些控件)会把发生在自己身上的事件截获,而不会再向上传递给自己的父控件.
  回复  引用    
#31楼2008-10-06 02:08 | XiiL[未注册用户]
应该是Button不再响应MouseLeftButtonDown(UP)事件.
  回复  引用  查看    
#32楼2008-11-07 15:43 | 戏水      
CaptureMouse()

ReleaseMouseCapture()
是做什么呢? 我注释掉这两行 貌似也没啥影响啊?
会军兄给解释解释吧

  回复  引用  查看    
#33楼[楼主]2008-11-07 23:39 | TerryLee      
@戏水
捕捉或者释放鼠标。

PS:不太确定在RTW下是不是还有它们?

  回复  引用    
#34楼2008-11-16 06:37 | 风绪[未注册用户]
为什么需要捕捉鼠标呢?
不捕捉也可以移动,是否是版本不同的原因?
Point mousePoint;
bool move;

private void panel_MouseMove(object sender, MouseEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;

if (move)
{
Canvas.SetLeft(element, Canvas.GetLeft(element) + e.GetPosition(null).X - mousePoint.X);
Canvas.SetTop(element, Canvas.GetTop(element) + e.GetPosition(null).Y - mousePoint.Y);

mousePoint = e.GetPosition(null);
}
}

private void panel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
mousePoint = e.GetPosition(null);
move = true;
}

private void panel_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
move = false;
}

  回复  引用    
#35楼2008-12-02 13:39 | u father[未注册用户]
nnd,这个东西能动吗?
  回复  引用    
#36楼2008-12-02 19:35 | 冻结2[未注册用户]
@风绪
为什么需要捕捉鼠标/释放捕获鼠标呢?

1.在鼠标按下的时候(MouseLeftButtonDown)执行捕获鼠标(CaptureMouse),这就好比告诉鼠标“当前鼠标正在对该对象操作”,以至于鼠标移动的时候(MouseMove),既便脱离该对象,也依然会出发该对象的MouseMove事件。

2.同理,鼠标松开的时候(MouseLeftButtonUp)必须要释放捕获的鼠标,以便鼠标可以操作其它对象,这就好比告诉鼠标“你不要操作我了,你可以喝咖啡去了”,这样鼠标再移动的时候(MouseMove),也不会再操作该对象。

你可以做个简单的实验,不加捕获鼠标/释放捕获鼠标,鼠标按下后,迅速移动鼠标,你会看到什么现象?是不是鼠标离开对象就失去作用了?

  回复  引用  查看    
#37楼2008-12-03 13:02 | Z-Suker      
会军大哥,我装的是SilverLight2.0的beta2版~怎么你第5章的例子运行不了呢???感觉beta1和beta2好多地方有差别啊.......会军大哥,帮帮忙说下怎么在beta2版里让button移动啊~~~~~~~~~~
  回复  引用    
#38楼2008-12-04 01:36 | 冻结2[未注册用户]
@Z-Suker
sl2.0bate2和sl2.0正式版的button都不能移动了,会军大哥也说了这是事件路由的问题,
你刻意把button改为Rectangle,Ellipse或者其他控件,

  回复  引用  查看    
#39楼[楼主]2008-12-08 10:55 | TerryLee      
@Z-Suker
看看官方文档吧,那里面有一个示例,现在已经RTW了,怎么你还用Beta 2呢?

  回复  引用  查看    
#40楼2008-12-08 11:03 | Z-Suker      
--引用--------------------------------------------------
TerryLee: @Z-Suker
看看官方文档吧,那里面有一个示例,现在已经RTW了,怎么你还用Beta 2呢?
--------------------------------------------------------
那我现在装的Beta 2工具是不是全部要重新换成RTW版的啊???

  回复  引用    
#41楼2008-12-13 09:51 | 许东生[未注册用户]
怎么我的不动啊?
  回复  引用  查看    
#42楼[楼主]2008-12-15 11:38 | TerryLee      
@Z-Suker
是的

  回复  引用  查看    
#43楼[楼主]2008-12-15 11:39 | TerryLee      
@许东生
换成Rectangle就可以了,这跟Button的路由事件有关。

  回复  引用  查看    
#44楼2009-01-20 15:51 | 贝蒂      
--引用--------------------------------------------------
ChMal: beta2 中用Button的子控件StackPanel的MouseLeftButtonUp和MouseLeftButtonDown事件就可以实现了。因为控件的事件是向上传递的。
--------------------------------------------------------

是用了StackPanel可是好像还是有点问题呢,好像没有移动!

  回复  引用  查看    
#45楼2009-01-20 15:52 | 贝蒂      
--引用--------------------------------------------------
冻结2: @风绪
为什么需要捕捉鼠标/释放捕获鼠标呢?

1.在鼠标按下的时候(MouseLeftButtonDown)执行捕获鼠标(CaptureMouse),这就好比告诉鼠标“当前鼠标正在对该对象操作”,以至于鼠标移动的时候(MouseMove),既便脱离该对象,也依然会出发该对象的MouseMove事件。

2.同理,鼠标松开的时候(MouseLeftButtonUp)必须要释放捕获的鼠标,以便鼠标可以操作其它对象,这就好比告诉鼠标“你不要操作我了,你可以喝咖啡去了”,这样鼠标再移动的时候(MouseMove),也不会再操作该对象。

你可以做个简单的实验,不加捕获鼠标/释放捕获鼠标,鼠标按下后,迅速移动鼠标,你会看到什么现象?是不是鼠标离开对象就失去作用了?
--------------------------------------------------------
这个试过了,是像你说的那样唉!^_^3Q!

  回复  引用    
#46楼2009-02-19 14:57 | xmonkey[未注册用户]
李大哥,您好!
我们在做SilverLight应用的时候遇上一个问题,想请教一下您。具体的需求是这样的:

我们用SilverLight做了一个Web的流程设计器,然后现在我们在做出了一幅流程图后,想说实现拖拉某个节点(自己做的一个图形)到某一条路径(一个Path的对象)上面,就可以实现把节点加到路径上,并且这时路径会变成两条,连接在拖进去的节点和原来的头尾节点上。譬如,A---------->B,然后我把C拖到A、B之间的路径上,然后释放鼠标,就会自动变成A-------->C---------->B。

我们现在主要的问题就是不知道怎么捕捉到控件进入路径的时刻,我们只想到说捕捉鼠标进入路径的事件,就是Path的Mouse_Enter。但是这样的话,感觉局限比较大。

有没有更好的办法去捕捉这一事件,或者说其他方法来实现这个需求呢?

谢谢!期待你的回复!

  回复  引用  查看    
#47楼2009-03-10 10:16 | 张智清      
确实是我的SL2.0正式版也是不能拖放的,按照sdk文档,换成Rectangle就可以了。
  回复  引用    
#48楼2009-04-09 17:55 | 啊 [未注册用户]
@ChMal
怎么不行

  回复  引用    
#49楼2009-04-10 10:48 | KevinZhang[未注册用户]
Mouse有ClickMode属性,默认为为pressed,选其他两个属性值,可以激发mouseleftdown和mouseleftup事件
  回复  引用    
#50楼2009-04-24 18:07 | LoveSilverlight[未注册用户]
的确对于SilverLight2 ,在XAML中定义<Button>时,需要将ClickMode="Hover" ,即可触发Mouseleftdown和Mouseleftup事件,本例中的代码也能正常执行!
<Button ClickMode="Hover" Mouseleftdown=xxxx >

</Button>

即可!


  回复  引用    
#51楼2009-04-25 17:00 | sl3[未注册用户]
LoveSilverlight
太强悍了,果然能动了,谢谢

  回复  引用  查看    
#52楼2009-05-04 13:56 | 杜辉      
--引用--------------------------------------------------
LoveSilverlight: 的确对于SilverLight2 ,在XAML中定义&lt;Button&gt;时,需要将ClickMode=&quot;Hover&quot; ,即可触发Mouseleftdown和Mouseleftup事件,本例中的代码也能正常执行!
&lt;Button ClickMode=&quot;Hover&quot; Mouseleftdown=xxxx &gt;

&lt;/Button&gt;

即可!


--------------------------------------------------------
的确可以了

  回复  引用  查看    
#53楼2009-05-11 14:54 | xihongshibeibei      
@LoveSilverlight
果然能动了

  回复  引用    
#54楼2009-05-23 11:48 | 风生竹韵
呵呵,谢谢博主的文章。
  回复  引用    
#55楼2009-05-26 10:02 | chenzhihua[未注册用户]
如果我在Button外面加一个Canvas,定义这个Canvas的高宽,那么为什么不是在这个Canvas内实现局部拖放呢,而是全屏的呢?谢谢!
  回复  引用  查看    
#56楼2009-06-23 10:17 | 水星      
en 很不错
  回复  引用    
#57楼2009-06-24 13:23 | Ruaidhir[未注册用户]
@LoveSilverlight
正解!~
由于 ButtonBase 类处理鼠标事件的方式,当单击模式是 Hover 以外的值时,不会发生 MouseLeftButtonDown 和 MouseLeftButtonUp 事件。




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1096008




相关文章:

相关链接: