Dragging A Control - Limits
-
I have a WPF canvas that is as wide as the window, and want the user to be able to drag it to the right pas the right edge, but no more left than its original position. Here's what I have so far:
private void root_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var element = sender as FrameworkElement;
anchorPoint = e.GetPosition(null);
element.CaptureMouse();
isDragging = true;
e.Handled = true;
}private void root_MouseMove(object sender, MouseEventArgs e)
{
if (isDragging)
{
Canvas element = sender as Canvas;
currentPoint = e.GetPosition(null);transform.X += currentPoint.X - anchorPoint.X; transform.Y = transform.Y; innerCanvas.RenderTransform = transform; anchorPoint = currentPoint; }
}
private void root_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (isDragging)
{
var element = sender as FrameworkElement;
element.ReleaseMouseCapture();
isDragging = false;
e.Handled = true;
}
}I've tried this in MouseMove:
if (currentPoint.X - anchorPoint.X > -1)
{
transform.X += currentPoint.X - anchorPoint.X;
transform.Y = transform.Y;
innerCanvas.RenderTransform = transform;
anchorPoint = currentPoint;
}but the control only moves once, and then no more at all after that. How do I keep the control from being move to the left so that its right edge is never past the window's right edge?
If it's not broken, fix it until it is
-
I have a WPF canvas that is as wide as the window, and want the user to be able to drag it to the right pas the right edge, but no more left than its original position. Here's what I have so far:
private void root_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var element = sender as FrameworkElement;
anchorPoint = e.GetPosition(null);
element.CaptureMouse();
isDragging = true;
e.Handled = true;
}private void root_MouseMove(object sender, MouseEventArgs e)
{
if (isDragging)
{
Canvas element = sender as Canvas;
currentPoint = e.GetPosition(null);transform.X += currentPoint.X - anchorPoint.X; transform.Y = transform.Y; innerCanvas.RenderTransform = transform; anchorPoint = currentPoint; }
}
private void root_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (isDragging)
{
var element = sender as FrameworkElement;
element.ReleaseMouseCapture();
isDragging = false;
e.Handled = true;
}
}I've tried this in MouseMove:
if (currentPoint.X - anchorPoint.X > -1)
{
transform.X += currentPoint.X - anchorPoint.X;
transform.Y = transform.Y;
innerCanvas.RenderTransform = transform;
anchorPoint = currentPoint;
}but the control only moves once, and then no more at all after that. How do I keep the control from being move to the left so that its right edge is never past the window's right edge?
If it's not broken, fix it until it is
I'm less at sub-novice level with WPF but I would imagine that the general principles for solving this problem will much the same as with System.Windows.Forms. Rather than attempting to calculate if an arbitrary new position is valid we can simply limit the mouse movement so that all achievable positions become ok. 1) On mouse button down calculate and set a constraining rectangle for the cursor 2) In mouse move relocate the label based on an offset from the cursor position 3) On losing mouse capture remove the constraining reactangle Here's one I prepared earlier. It should compile and run:
using System;
using System.Drawing;
using System.Windows.Forms;namespace MouseMoveLabelDemo {
public sealed class DemoForm : Form {
[STAThread]
private static void Main() {
Application.Run(new DemoForm());
}private readonly Point home; private Label itinerantLabel; private Size offset; public DemoForm() { home = new Point(10, 10); BackColor = Color.White; itinerantLabel = new Label(); itinerantLabel.Text = "Move Me"; itinerantLabel.BackColor = Color.Pink; itinerantLabel.BorderStyle = BorderStyle.FixedSingle; itinerantLabel.Location = home; itinerantLabel.Parent = this; itinerantLabel.MouseDown += Label\_MouseDown; itinerantLabel.MouseMove += Label\_MouseMove; itinerantLabel.MouseCaptureChanged += Label\_CaptureLost; SizeChanged += DemoForm\_SizeChanged; } private void DemoForm\_SizeChanged(object sender, EventArgs e) { // In this simple demo we don't want to lose the label // so just send it home whenever the form is resized itinerantLabel.Location = home; } private void Label\_MouseDown(object sender, MouseEventArgs e) { Label lbl = (Label)sender; if (e.Button == MouseButtons.Left) { // Mouse is automatically captured on mouse down // All manipulations in Screen coordinates Point cursorPosition = Cursor.Position; Point labelPosition = PointToScreen(lbl.Location); // calculate offset of cursor from label origin offset = new Size(cursorPosition.X - labelPosition.X, cursorPosition.Y - labelPosition.Y); // Constrain cursor within a part of the ClientRectangle // (x1, y1) - (x2, y2) Rectangle cursorClippingRectangle = Rectangle.FromLTRB( // x1 offset.Width, // y1 offset.Height,