拖拽WPF元件
原文出处:http://blogs.msdn.com/marcelolr/archive/2006/03/02/542641.aspx 这是介绍心爱的UI gesture(dragging和dropping)系列的第一篇帖子
在这第一篇的帖子中,我们会考察最简单的,最直接的方法:增加一系列的窗口事件处理器来更新布局属性.我将会使用VB.NET-转换到C#应该不是很困难的.(译者:因为不懂vb,代码会直接翻译成c#)
第一,我们从window1.xaml的代码开始.
<Window x:Class="SimpleDrapElement.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SimpleDrapElement" Height="300" Width="300"
>
<DockPanel>
<Border DockPanel.Dock="Top" BorderBrush="DarkGray" BorderThickness="2" Padding="4">
<TextBlock FontSize="8pt" FontFamily="Tahoma" TextWrapping="Wrap">
<Bold>
Drag Canvas Sample
</Bold>
<LineBreak />
<Run>
This sample demonstrates using adorners to drag shapes (or any other element).
</Run>
</TextBlock>
</Border>
<Canvas Name="MyCanvas">
<Canvas.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Color="White" Offset="0" />
<GradientStop Color="DarkBlue" Offset="1" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Canvas.Background>
<TextBox Canvas.Top="120" Canvas.Left="8" />
<Rectangle Canvas.Top="8" Canvas.Left="8"
Width="32" Height="32" Fill="LightPink" />
<Ellipse Canvas.Top="8" Canvas.Left="48"
Width="40" Height="16" Fill="Tan" />
<Rectangle Canvas.Top="48" Canvas.Left="8"
Width="32" Height="62" Fill="Green" />
<Ellipse Canvas.Top="48" Canvas.Left="48"
Width="62" Height="62" Fill="Orange" />
</Canvas>
</DockPanel>
</Window>
创建了一个简单的窗口,看起来就象这样:
好了,现在让我们挽起袖子,一点一点的往window1.xaml.cs里添加代码.
首先,从window1的constructor正下方开始,我们增加一些代码.
private Point m_StartPoint;// Where did the mouse start off from?
private Double m_OriginalLeft;// What was the element;//s original x offset?
private Double m_OriginalTop;// What was the element;//s original y offset?
private Boolean m_IsDown;// Is the mouse down right now?
private Boolean m_IsDragging;// Are we actually dragging the shape around?
private UIElement m_OriginalElement;// What is it that we;//re dragging?
private Rectangle m_OverlayElement;// What is it that we;//re using to show where the shape will end up?
这就是我们所要探知的如何在Canvas上移动shapes的信息.
{
if (e.Source == MyCanvas)
{
return;
}
m_IsDown = true;
m_StartPoint = e.GetPosition(MyCanvas);
m_OriginalElement = e.Source as UIElement;
MyCanvas.CaptureMouse();
e.Handled = true;
}
private void MyCanvas_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (m_IsDown)
{
if (!m_IsDragging &&
Math.Abs(e.GetPosition(MyCanvas).X - m_StartPoint.X) > SystemParameters.MinimumHorizontalDragDistance &&
Math.Abs(e.GetPosition(MyCanvas).Y - m_StartPoint.Y) > SystemParameters.MinimumVerticalDragDistance)
{
DragStarted();
}
if (m_IsDragging)
{
DragMoved();
}
}
}
有几件事需要注意的:点击鼠标时我们获取了鼠标(万一用户把鼠标移动到边界外),和DrapStarted(),DragMoved()中使用的 helper方法.另外也必须要注意,考虑到用户的选择,我们使用系统参数的开始拖拽距离设置.这个对笔记本与平板电脑特别有用,因为使用鼠标棒和鼠标板时是很容易引起鼠标晃动的.
现在,要在我们的helper方法中做什么呢?
{
m_IsDragging = true;
m_OriginalLeft = Canvas.GetLeft(m_OriginalElement);
m_OriginalTop = Canvas.GetTop(m_OriginalElement);
VisualBrush brush = new VisualBrush(m_OriginalElement);
brush.Opacity = 0.5;
m_OverlayElement = new Rectangle();
m_OverlayElement.Width = m_OriginalElement.RenderSize.Width;
m_OverlayElement.Height = m_OriginalElement.RenderSize.Height;
m_OverlayElement.Fill = brush;
MyCanvas.Children.Add(m_OverlayElement);
}
private void DragMoved()
{
Point currentPosition = Mouse.GetPosition(MyCanvas);
double elementLeft = currentPosition.X - m_StartPoint.X + m_OriginalLeft;
double elementTop = currentPosition.Y - m_StartPoint.Y + m_OriginalTop;
Canvas.SetLeft(m_OverlayElement, elementLeft);
Canvas.SetTop(m_OverlayElement, elementTop);
}
注意我是如何使用透明的VisulaBrush来显示最终的shape.另外,由于我们使用的是Canvas,所以只要改变Left和top属性.如果是 DockPanel,我将会尝试是否呢个能够snapping边界,或者如果是Grid,我将会试着指出shape要放下的格子.我只是研究了最简单的一个例子,你们自己可以继续深入.
这已经很好了,但我们如何放下shape呢?有两种典型做法,一个是释放鼠标按钮,另一个是按下esc键.让我们来编写它:
private void MyCanvas_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (m_IsDown)
{
DragFinished(false);
e.Handled = true;
}
}
private void Window1_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape && m_IsDragging)
{
DragFinished(true);
}
}
另外,一个helper方法很明了的显示了当我们停止拖拽时都发生了什么,这里是它的实现:
{
Mouse.Capture(null);
if (m_IsDragging)
{
MyCanvas.Children.Remove(m_OverlayElement);
if (!canceled)
{
Canvas.SetLeft(m_OriginalElement, Canvas.GetLeft(m_OverlayElement));
Canvas.SetTop(m_OriginalElement, Canvas.GetTop(m_OverlayElement));
}
m_OverlayElement = null;
}
m_IsDragging = false;
m_IsDown = false;
}
我亲爱的读者们.今天的例子结束了.试着实现,扩展一下他们,惊讶于他们半透明的预览.你能否添加其它的控件来拖拽呢?
(以下非翻译内容)
由于改了c#代码,所以要在Window1的构造函数要修改为:
public Window1()
{
InitializeComponent();
MyCanvas.PreviewMouseLeftButtonDown += MyCanvas_PreviewMouseLeftButtonDown;
MyCanvas.PreviewMouseMove += MyCanvas_PreviewMouseMove;
MyCanvas.PreviewMouseLeftButtonUp += MyCanvas_PreviewMouseLeftButtonUp;
this.PreviewKeyDown += Window1_PreviewKeyDown;
}
代码下载:
share your files at box.net