概述
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;
}
效果显示
最终,完成后的效果如下
拖动按钮
结束语
本文实现了一个简单的拖放功能(示例来自于Silverlight 2 SDK),点击下载文本示例代码。
下一篇:一步一步学Silverlight 2系列(6):键盘事件处理
posted @ 2008-03-08 00:40
TerryLee 阅读(19172)
评论(83) 编辑 收藏 网摘 所属分类:
[03] 银光点亮世界
发表评论
GetPosition(relativeTo)函数里的参数是表示位置是相对于relativeTo参数对象的
你上面的实例里GetPosition(null),这个怎样理解的?
明了
To specify the object relative to the overall Silverlight coordinate system, set the relativeTo parameter to null.
Silverlight2.0也没有内置拖放支持,这点让人比较失望……
#4楼[
楼主]2008-03-20 09:06 |
@Cat Chen
是啊,现在只能是靠鼠标事件来控制元素的位置实现拖放
Silverlight 2 SDK 有没有中文的了?可不可以给个地址出来呢?
#8楼[
楼主]2008-06-17 22:58 |
@房客
该系列文章的环境是Beta 1!
嗯。我知道,我只是说出你的例子在Beta2中可能出现的问题,让我们后来学习的人不要在beta2中死钻这个问题,我调了半天才发现的。
我调试了下,好像是在程序中不可以设置Canvas的属性。比如:
SetValue(Canvas.LeftProperty, 100);
#10楼[
楼主]2008-06-18 00:00 |
@房客
Beta 2中SetValue方法修改过了,不可以直接指定一个double类型的值,需要转换为Object对象才行。
#11楼[
楼主]2008-06-18 00:11 |
OnMouseDown和OnMouseUp在Beta2的环境下无法触发,不知道Beta1有没有这个问题?但OnMouseMove可以触发,非常奇怪!
确实OnMouseDown和OnMouseUp在Beta2的环境下无法触发
最近开始看这个系列的教程,我用的是beta2的,好像mousedown和mouseup在beta2中并不是完全不能用的,Button组件是不行的,不过我在一个IMAGE组件的这两个事件添加了这些代码之后,可以实现拖动的
难道这个跟控件类型有关?
没错,在beta2中,Button 控件不能实现拖放操作,但是其它控件似乎可以,比TextBlock 、Image 等。
#17楼[
楼主]2008-06-26 09:56 |
@Goumh
不是不可以,是在事件处理机制上有些变化。。,有空我会详细解释一下。
貌似在BETA 2中,按钮没有MouseLeftButtonDown,和MouseLeftButtonUp事件吧。
@阿胜
事件同样是存在的,只是添加了事件代码之后却不会被触发
等待楼主的讲解吧
#22楼[
楼主]2008-07-21 10:22 |
@garf
这个似乎也没有多少难的,主要在鼠标事件里面控制一下动画,可以在Silverlight.net网站上找到类似的例子。。。
buttong在Beta2中不能拖动了,改成Image就可以拖动了
================================================
<UserControl....>
<Canvas Background="#46461F">
<Image Source="smile_6.png"
MouseLeftButtonDown="OnMouseDown"
MouseMove="OnMouseMove"
MouseLeftButtonUp="OnMouseUp"/>
</Canvas>
</UserControl>
beta2 中用Button的子控件StackPanel的MouseLeftButtonUp和MouseLeftButtonDown事件就可以实现了。因为控件的事件是向上传递的。
@TerryLee
Beta 2中SetValue方法修改过了,不可以直接指定一个double类型的值,需要转换为Object对象才行。
这个好像直接传递double值,也可以执行。
回各位好朋友!
在进行阅读楼主的博文时,在实际的操作中确实出现了在Beta2版本中Button无MouseLeftButtonDown和MouseLeftButtonUp这两个事件。
如果把Button换成StackPanel,博主的代码不用进行修改是可以执行成功的!
有遇到和我类似问题的朋友们可以尝试测试下!
把MouseLeftButtonDown和MouseLeftButtonUp这两个事件移到StackPanel下, 确实可以运行. 但是偶尔会无法触发事件而拖不动.要多按几下才又拖的动. 有人知道为何吗?
#28楼[
楼主]2008-09-17 00:58 |
@Nick Lee
可能是事件路由的问题。
@Nick Lee
因为StackPanel并不是平铺到整个Button控件上,只是紧凑包围了内容,你把鼠标点在内容上,如图片、文字,就可以执行事件了,如果点在Button的内容外面的空白区域,那些不是StackPanel的覆盖范围,则不执行事件
在Beta2中,Button(还有一些控件)会把发生在自己身上的事件截获,而不会再向上传递给自己的父控件.
应该是Button不再响应MouseLeftButtonDown(UP)事件.
CaptureMouse()
和
ReleaseMouseCapture()
是做什么呢? 我注释掉这两行 貌似也没啥影响啊?
会军兄给解释解释吧
#33楼[
楼主]2008-11-07 23:39 |
@戏水
捕捉或者释放鼠标。
PS:不太确定在RTW下是不是还有它们?
为什么需要捕捉鼠标呢?
不捕捉也可以移动,是否是版本不同的原因?
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;
}
@风绪
为什么需要捕捉鼠标/释放捕获鼠标呢?
1.在鼠标按下的时候(MouseLeftButtonDown)执行捕获鼠标(CaptureMouse),这就好比告诉鼠标“当前鼠标正在对该对象操作”,以至于鼠标移动的时候(MouseMove),既便脱离该对象,也依然会出发该对象的MouseMove事件。
2.同理,鼠标松开的时候(MouseLeftButtonUp)必须要释放捕获的鼠标,以便鼠标可以操作其它对象,这就好比告诉鼠标“你不要操作我了,你可以喝咖啡去了”,这样鼠标再移动的时候(MouseMove),也不会再操作该对象。
你可以做个简单的实验,不加捕获鼠标/释放捕获鼠标,鼠标按下后,迅速移动鼠标,你会看到什么现象?是不是鼠标离开对象就失去作用了?
会军大哥,我装的是SilverLight2.0的beta2版~怎么你第5章的例子运行不了呢???感觉beta1和beta2好多地方有差别啊.......会军大哥,帮帮忙说下怎么在beta2版里让button移动啊~~~~~~~~~~
@Z-Suker
sl2.0bate2和sl2.0正式版的button都不能移动了,会军大哥也说了这是事件路由的问题,
你刻意把button改为Rectangle,Ellipse或者其他控件,
#39楼[
楼主]2008-12-08 10:55 |
@Z-Suker
看看官方文档吧,那里面有一个示例,现在已经RTW了,怎么你还用Beta 2呢?
--引用--------------------------------------------------
TerryLee: @Z-Suker
看看官方文档吧,那里面有一个示例,现在已经RTW了,怎么你还用Beta 2呢?
--------------------------------------------------------
那我现在装的Beta 2工具是不是全部要重新换成RTW版的啊???
#42楼[
楼主]2008-12-15 11:38 |
@Z-Suker
是的
#43楼[
楼主]2008-12-15 11:39 |
@许东生
换成Rectangle就可以了,这跟Button的路由事件有关。
--引用--------------------------------------------------
ChMal: beta2 中用Button的子控件StackPanel的MouseLeftButtonUp和MouseLeftButtonDown事件就可以实现了。因为控件的事件是向上传递的。
--------------------------------------------------------
是用了StackPanel可是好像还是有点问题呢,好像没有移动!
--引用--------------------------------------------------
冻结2: @风绪
为什么需要捕捉鼠标/释放捕获鼠标呢?
1.在鼠标按下的时候(MouseLeftButtonDown)执行捕获鼠标(CaptureMouse),这就好比告诉鼠标“当前鼠标正在对该对象操作”,以至于鼠标移动的时候(MouseMove),既便脱离该对象,也依然会出发该对象的MouseMove事件。
2.同理,鼠标松开的时候(MouseLeftButtonUp)必须要释放捕获的鼠标,以便鼠标可以操作其它对象,这就好比告诉鼠标“你不要操作我了,你可以喝咖啡去了”,这样鼠标再移动的时候(MouseMove),也不会再操作该对象。
你可以做个简单的实验,不加捕获鼠标/释放捕获鼠标,鼠标按下后,迅速移动鼠标,你会看到什么现象?是不是鼠标离开对象就失去作用了?
--------------------------------------------------------
这个试过了,是像你说的那样唉!^_^3Q!
李大哥,您好!
我们在做SilverLight应用的时候遇上一个问题,想请教一下您。具体的需求是这样的:
我们用SilverLight做了一个Web的流程设计器,然后现在我们在做出了一幅流程图后,想说实现拖拉某个节点(自己做的一个图形)到某一条路径(一个Path的对象)上面,就可以实现把节点加到路径上,并且这时路径会变成两条,连接在拖进去的节点和原来的头尾节点上。譬如,A---------->B,然后我把C拖到A、B之间的路径上,然后释放鼠标,就会自动变成A-------->C---------->B。
我们现在主要的问题就是不知道怎么捕捉到控件进入路径的时刻,我们只想到说捕捉鼠标进入路径的事件,就是Path的Mouse_Enter。但是这样的话,感觉局限比较大。
有没有更好的办法去捕捉这一事件,或者说其他方法来实现这个需求呢?
谢谢!期待你的回复!
确实是我的SL2.0正式版也是不能拖放的,按照sdk文档,换成Rectangle就可以了。
Mouse有ClickMode属性,默认为为pressed,选其他两个属性值,可以激发mouseleftdown和mouseleftup事件
的确对于SilverLight2 ,在XAML中定义<Button>时,需要将ClickMode="Hover" ,即可触发Mouseleftdown和Mouseleftup事件,本例中的代码也能正常执行!
<Button ClickMode="Hover" Mouseleftdown=xxxx >
</Button>
即可!
LoveSilverlight
太强悍了,果然能动了,谢谢
--引用--------------------------------------------------
LoveSilverlight: 的确对于SilverLight2 ,在XAML中定义<Button>时,需要将ClickMode="Hover" ,即可触发Mouseleftdown和Mouseleftup事件,本例中的代码也能正常执行!
<Button ClickMode="Hover" Mouseleftdown=xxxx >
</Button>
即可!
--------------------------------------------------------
的确可以了
如果我在Button外面加一个Canvas,定义这个Canvas的高宽,那么为什么不是在这个Canvas内实现局部拖放呢,而是全屏的呢?谢谢!
@LoveSilverlight
正解!~
由于 ButtonBase 类处理鼠标事件的方式,当单击模式是 Hover 以外的值时,不会发生 MouseLeftButtonDown 和 MouseLeftButtonUp 事件。
真的感谢各位的讨论,在学习楼主的文章时候出现的各种问题,只要看看大家的讨论是肯定能解决的,今天的这篇文章就是版本升级后由于clickmode必须增加hover属性导致。不过有一楼提出的用image直接就可以,可见大家都对楼主的文章确实的感兴趣,兄弟也同大家一样,刚来学习,希望指导,邮箱:cuiyihao@yahoo.com.cn
怪事,我将 ClickMode="Hover" 也不能拖动,设计时用Silverlight2,播放器是Silverlight 3.0的
你用的东西不对的,设计时候用silverlight2,你装tools的时候也装2的工具包,不然的话,估计就弄不成,我刚开到网站上下载的3.0装的时候老出问题。
@LoveSilverlight
确实啊,修改clickmode即可。。
李大哥,我遇到一个问题,想向您请教一下:
我实现了Border控件的拖放效果,但是有个BUG。因为我这个Border控件下有个Grid,这个Grid有个子控件DataGrid,当我鼠标处于DataGrid的空白区域时,能实现拖放,但当鼠标位于该DataGrid的列头时,却只能拖了,放开鼠标还是能拖动,而且鼠标指针也没变成Hand,我想了很多方法都解决不了,希望李大哥能帮解决一下,谢谢~
在 SL3中 button 不响应 MouseLeftButtonDown 事件!!
好啊 看了诸位的留言 问题也得到了解决 也感谢lz为大家提供了一个很好的讨论场!
郁闷了 为什么我的那个笑脸图片显示不出来啊 我是把图片放在和这个xaml文件同级的目录的 跪求解释
---------------------------------------------------
的确是这样
非常好!
我用的silverlight3.0,加clickMode="Hover",两个事件即可触发,搞定!
silverlight3.0
为什么我一拖。控件就飞了?额。。代码和楼主一样的。