在Silverlight中,要实现拖动对象的功能最简单的方式是采用Canvas做为父容器,通过动态的改变元素的附加属性Top、Left即可实现拖动同能。如图所示:
下例所示:
XAML:
<UserControl x:Class="DragExample.MainPage" 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" mc:Ignorable="d" d:DesignHeight="500" d:DesignWidth="600"> <Canvas x:Name="LayoutRoot" Background="Gray"> <Ellipse x:Name="ellipse" Canvas.Left="300" Canvas.Top="300" Width="100" Height="100" Stroke="YellowGreen" Fill="White" StrokeThickness="5" MouseLeftButtonDown="ellipse_MouseLeftButtonDown" MouseMove="ellipse_MouseMove" MouseLeftButtonUp="ellipse_MouseLeftButtonUp"></Ellipse> </Canvas> </UserControl>
CS:
public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } /// <summary> /// 标识是否可以拖动对象 /// </summary> private bool isDrag = false; private void ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { isDrag = true; ellipse.CaptureMouse(); } private void ellipse_MouseMove(object sender, MouseEventArgs e) { if (isDrag) { Point position = e.GetPosition(LayoutRoot);
//通过绝对位置定位 Canvas.SetLeft(ellipse, position.X); Canvas.SetTop(ellipse, position.Y); } } private void ellipse_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { isDrag = false; } }
运行效果:
通过使用,即可发现:在体验方面不是很逼真,鼠标指针在移动的过程中,始终处于圆的左上角,即(Left,Top)坐标处。那么如何完善,使鼠标不乱处于圆的任何位置,都能表现出真实的移动过程。可以计算相对移动位置,即可解决。演示图:
如下所示:
public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } /// <summary> /// 标识是否可以拖动对象 /// </summary> private bool isDrag = false; private Point StartPoint; private Point EndPoint; private void ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { isDrag = true; StartPoint = e.GetPosition(LayoutRoot); ellipse.CaptureMouse(); } private void ellipse_MouseMove(object sender, MouseEventArgs e) { if (isDrag) { EndPoint = e.GetPosition(LayoutRoot); //计算X、Y轴起始点与终止点之间的相对偏移量 double y = EndPoint.Y - StartPoint.Y; double x = EndPoint.X - StartPoint.X; Point position = new Point((double)Canvas.GetLeft(ellipse), (double)Canvas.GetTop(ellipse)); //计算(Left,Top)坐标相对移动的目标坐标位置 position.X = position.X + x; position.Y = position.Y + y; Canvas.SetLeft(ellipse, position.X); Canvas.SetTop(ellipse, position.Y); StartPoint = EndPoint; } } private void ellipse_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { isDrag = false; } }
运行效果:
以上是通过Canvas作为容器,实现元素拖动的功能,但是,使用Canvas作为父容器有一个缺陷就是:子元素不能够自动水平垂直居中显示, 需要一定的数学计算分析才能够居中,如果以当前圆所在位置的圆心为坐标,实现放大缩小功能,而不是以(Left,Top)为圆放大缩小目标点,有什么好的 解决方案??
第二种方法,可以通过动态计算Margin的Left、Top、Right、Bottom设置的值即可实现多动功能。
以Grid为父容器,XAML:
<Grid x:Name="LayoutRoot" Background="Gray"> <Ellipse x:Name="ellipse" Width="100" Height="100" Stroke="YellowGreen" Fill="White" StrokeThickness="5" MouseLeftButtonDown="ellipse_MouseLeftButtonDown" MouseMove="ellipse_MouseMove" MouseLeftButtonUp="ellipse_MouseLeftButtonUp"></Ellipse> </Grid>
CS:
public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } /// <summary> /// 标识是否可以拖动对象 /// </summary> private bool isDrag = false; private Point StartPoint; private Point EndPoint; private void ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { isDrag = true; StartPoint = e.GetPosition(LayoutRoot); ellipse.CaptureMouse(); } private void ellipse_MouseMove(object sender, MouseEventArgs e) { if (isDrag) { EndPoint = e.GetPosition(LayoutRoot); //计算X、Y轴起始点与终止点之间的相对偏移量 double y = EndPoint.Y - StartPoint.Y; double x = EndPoint.X - StartPoint.X; Thickness margin = ellipse.Margin; //计算新的Margin Thickness newMargin = new Thickness() { Left = margin.Left + x, Top = margin.Top + y, Right = margin.Right - x, Bottom = margin.Bottom - y }; ellipse.Margin = newMargin; StartPoint = EndPoint; } } private void ellipse_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { isDrag = false; } }
运行效果:
第三种方案:利用Expression Blend 4的MouseDragElementBehavior,将此附加到元素上即可实现自由拖动。以上是对Silverlight拖动的总结,还有其他方案?