protected bool isDragging;
private Point clickPosition;
然后在控件的建构函式中附加一些事件行程常式:
this.MouseLeftButtonDown += new MouseButtonEventHandler(Control_MouseLeftButtonDown);
this.MouseLeftButtonUp += new MouseButtonEventHandler(Control_MouseLeftButtonUp);
this.MouseMove += new MouseEventHandler(Control_MouseMove);
现在创建这些方法:
private void Control_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
isDragging = true;
var draggableControl = sender as UserControl;
clickPosition = e.GetPosition(this);
draggableControl.CaptureMouse();
}
private void Control_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
isDragging = false;
var draggable = sender as UserControl;
draggable.ReleaseMouseCapture();
}
private void Control_MouseMove(object sender, MouseEventArgs e)
{
var draggableControl = sender as UserControl;
if (isDragging && draggableControl != null)
{
Point currentPosition = e.GetPosition(this.Parent as UIElement);
var transform = draggableControl.RenderTransform as TranslateTransform;
if (transform == null)
{
transform = new TranslateTransform();
draggableControl.RenderTransform = transform;
}
transform.X = currentPosition.X - clickPosition.X;
transform.Y = currentPosition.Y - clickPosition.Y;
}
}
Button newBtn = new Button();
newBtn.AddHandler(Button.ClickEvent, new RoutedEventHandler(BtTable_Click));
newBtn.AddHandler(Button.PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(BtTable_MouseLeftButtonDown));
newBtn.AddHandler(Button.PreviewMouseLeftButtonUpEvent, new MouseButtonEventHandler(BtTable_MouseLeftButtonUp));
newBtn.AddHandler(Button.PreviewMouseMoveEvent, new MouseEventHandler(BtTable_MouseMove));
按钮移动
private object movingObject;
private double firstXPos, firstYPos;
private int ButtonSize = 50;
private void BtTable_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Button newBtn = sender as Button;
Canvas canvas = newBtn.Parent as Canvas;
firstXPos = e.GetPosition(newBtn).X;
firstYPos = e.GetPosition(newBtn).Y - ButtonSize;
movingObject = sender;
// Put the image currently being dragged on top of the others
int top = Canvas.GetZIndex(newBtn);
foreach (Button child in canvas.Children)
if (top < Canvas.GetZIndex(child))
top = Canvas.GetZIndex(child);
Canvas.SetZIndex(newBtn, top + 1);
Mouse.Capture(null);
}
private void BtTable_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Button newBtn = sender as Button;
Canvas canvas = newBtn.Parent as Canvas;
movingObject = null;
// Put the image currently being dragged on top of the others
int top = Canvas.GetZIndex(newBtn);
foreach (Button child in canvas.Children)
if (top > Canvas.GetZIndex(child))
top = Canvas.GetZIndex(child);
Canvas.SetZIndex(newBtn, top + 1);
Mouse.Capture(newBtn);
}
private void BtTable_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed && sender == movingObject)
{
Button newBtn = sender as Button;
Canvas canvas = newBtn.Parent as Canvas;
// Horizontal
double newLeft = e.GetPosition(canvas).X - firstXPos - canvas.Margin.Left;
// newLeft inside canvas right-border?
if (newLeft > canvas.Margin.Left + canvas.ActualWidth - newBtn.ActualWidth)
newLeft = canvas.Margin.Left + canvas.ActualWidth - newBtn.ActualWidth;
// newLeft inside canvas left-border?
else if (newLeft < canvas.Margin.Left)
newLeft = canvas.Margin.Left;
newBtn.SetValue(Canvas.LeftProperty, newLeft);
//Vertical
double newTop = e.GetPosition(canvas).Y - firstYPos - canvas.Margin.Top;
// newTop inside canvas bottom-border?
// -- Bottom --
if (newTop > canvas.Margin.Top + canvas.ActualHeight - newBtn.ActualHeight - ButtonSize)
newTop = canvas.Margin.Top + canvas.ActualHeight - newBtn.ActualHeight - ButtonSize;
// newTop inside canvas top-border?
// -- Top --
else if (newTop < canvas.Margin.Top - ButtonSize)
newTop = canvas.Margin.Top - ButtonSize;
newBtn.SetValue(Canvas.TopProperty, newTop);
}
}
public partial class DragUserControl : UserControl
{
public DragUserControl()
{
InitializeComponent();
}
object MovingObject;
double FirstXPos, FirstYPos;
private void Button_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.MovingObject = this;
FirstXPos = e.GetPosition(MovingObject as Control).X;
FirstYPos = e.GetPosition(MovingObject as Control).Y;
Canvas canvas = this.Parent as Canvas;
if (canvas != null)
{
canvas.PreviewMouseMove += this.MouseMove;
}
}
private void MouseMove(object sender, MouseEventArgs e)
{
/*
* In this event, at first we check the mouse left button state. If it is pressed and
* event sender object is similar with our moving object, we can move our control with
* some effects.
*/
Canvas canvas = sender as Canvas;
Point canvasPoint = e.GetPosition(canvas);
Point objPosition = e.GetPosition((MovingObject as FrameworkElement));
if (e.LeftButton == MouseButtonState.Pressed)
{
if (MovingObject != null)
{
//This condition will take care that control should not go outside the canvas.
if ((e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).X - FirstXPos > 0) && (e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).X - FirstXPos < canvas.ActualWidth - (MovingObject as FrameworkElement).ActualWidth))
{
(MovingObject as FrameworkElement).SetValue(Canvas.LeftProperty, e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).X - FirstXPos);
}
//This condition will take care that control should not go outside the canvas.
if ((e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).Y - FirstYPos > 0) && (e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).Y - FirstYPos < canvas.ActualHeight - (MovingObject as FrameworkElement).ActualHeight))
{
(MovingObject as FrameworkElement).SetValue(Canvas.TopProperty, e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).Y - FirstYPos);
}
}
}
}
private void Ellipse_PreviewMouseLeftButtonUp_1(object sender, MouseButtonEventArgs e)
{
MovingObject = null;
}
}
Button_MouseLeftButtonDown是要拖动控件的按钮的单击事件。
UWP
public sealed partial class DragUserControl : UserControl
{
MovingObject;
double FirstXPos, FirstYPos;
public DragUserControl()
{
InitializeComponent();
}
private void Ellipse_PointerPressed(object sender, PointerRoutedEventArgs e)
{
this.MovingObject = this;
FirstXPos = e.GetCurrentPoint(MovingObject as Control).Position.X;
FirstYPos = e.GetCurrentPoint(MovingObject as Control).Position.Y;
Canvas canvas = this.Parent as Canvas;
if (canvas != null)
{
canvas.PointerMoved += Canvas_PointerMoved;
}
}
private void Canvas_PointerMoved(object sender, PointerRoutedEventArgs e)
{
if (MovingObject != null)
{
Canvas canvas = sender as Canvas;
Point canvasPoint = e.GetCurrentPoint(canvas).Position;
Point objPosition = e.GetCurrentPoint((MovingObject as FrameworkElement)).Position;
if (e.GetCurrentPoint(MovingObject as Control).Properties.IsLeftButtonPressed) //e.Pointer.IsInContact ==true)
{
//This condition will take care that control should not go outside the canvas
if ((e.GetCurrentPoint((MovingObject as FrameworkElement).Parent as FrameworkElement).Position.X - FirstXPos > 0) && (e.GetCurrentPoint((MovingObject as FrameworkElement).Parent as FrameworkElement).Position.X - FirstXPos < canvas.ActualWidth - (MovingObject as FrameworkElement).ActualWidth))
{
(MovingObject as FrameworkElement).SetValue(Canvas.LeftProperty, e.GetCurrentPoint((MovingObject as FrameworkElement).Parent as FrameworkElement).Position.X - FirstXPos);
}
//This condition will take care that control should not go outside the canvas
if ((e.GetCurrentPoint((MovingObject as FrameworkElement).Parent as FrameworkElement).Position.Y - FirstYPos > 0) && (e.GetCurrentPoint((MovingObject as FrameworkElement).Parent as FrameworkElement).Position.Y - FirstYPos < canvas.ActualHeight - (MovingObject as FrameworkElement).ActualHeight))
{
(MovingObject as FrameworkElement).SetValue(Canvas.TopProperty, e.GetCurrentPoint((MovingObject as FrameworkElement).Parent as FrameworkElement).Position.Y - FirstYPos);
}
}
}
}
private void Ellipse_PointerReleased(object sender, PointerRoutedEventArgs e)
{
MovingObject = null;
}
}
8条答案
按热度按时间1tu0hz3e1#
这是在silverlight中完成的,而不是在WPF中,但它应该同样工作。
在控件上建立两个私用属性:
然后在控件的建构函式中附加一些事件行程常式:
现在创建这些方法:
这里需要注意几点:
1.它不一定要在画布中,也可以在堆栈面板或网格中。
2.这使得整个控件可拖动,这意味着如果您单击控件中的任何位置并拖动它,将拖动整个控件。不确定这是否正是您想要的。
编辑-
详述您问题中的一些细节:实现此功能的最佳方法是创建一个从UserControl继承的类,可能称为DraggableControl,它是使用此代码构建的,然后所有可拖动控件都应扩展DraggableControl。
编辑2 -当您在这个控件中有一个datagrid时,会有一个小问题。如果您在datagrid中排序一个栏,MouseLeftButtonUp事件永远不会触发。我已经更新了程式码,所以isDragging是受保护的。我发现最好的解决方案是将这个匿名方法系结到datagrid的LostMouseCapture事件:
3xiyfsfu2#
科里的回答基本正确,但缺少一个关键因素:否则,当您移动一个项目,释放鼠标按钮,然后再次单击该项目时,转换将重置为
(0,0)
,并且控件将跳回到其原点。这里有一个稍微修改过的版本,对我来说很有效:
关键是存储以前的X和Y偏移,然后使用它们来增加当前移动的偏移,以便达到正确的聚合偏移。
628mspwn3#
如果有人想尝试一个最小解决方案,这里有一个使用
MouseMove
事件的解决方案。布局
后面的代码
0kjbasz64#
关于 Corey Sunwold 解决方案-我去掉了MouseUp和MouseDown事件,并使用MouseButtonState简化了MouseMove方法,如下所示:)我使用Canvas.SetLeft()和Canvas.SetTop()代替RenderTransform,因此不需要存储MouseDown事件的旧位置。
0qx6xfy65#
Themelis更新了最小解代码,保留抓取位置:
pkwftd7m6#
我遇到了一些问题与给定的解决方案,并结束了这个:
它基本上是Corey的例子,但利用了Hawlett的提示。它只在父容器是Canvas时才起作用。而且,它值得用一些限制来修饰,以防止用户将控件拖到它真的不应该在的地方。
2nbm6dog7#
此代码完美运行!
按钮移动
fhg3lkii8#
我为WPF和UWP商店应用程序实现了这一点。并在用户控件本身而不是使用它的控件中添加了所有代码,您可以根据需要修改它。
世界粮食计划署
Button_MouseLeftButtonDown是要拖动控件的按钮的单击事件。
UWP
Ellipse_PointerPressed是要拖动控件的椭圆的单击事件。