Respuestas:
Este artículo sobre CodeProject detalla una técnica. Básicamente se reduce a:
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool ReleaseCapture();
private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
Básicamente, esto hace exactamente lo mismo que agarrar la barra de título de una ventana, desde el punto de vista del administrador de ventanas.
Form1_MouseDown
que no está asignado al MouseDown
evento real de Form1
.
this.MouseDown += ...
a la Main()
función para el formulario
No hagamos las cosas más difíciles de lo necesario. Me he encontrado con tantos fragmentos de código que le permiten arrastrar un formulario (u otro Control). Y muchos de ellos tienen sus propios inconvenientes / efectos secundarios. Especialmente aquellos en los que engañan a Windows para que piense que un Control en un formulario es el formulario real.
Dicho esto, aquí está mi fragmento. Lo uso todo el tiempo. También me gustaría señalar que no debería usar this.Invalidate (); como a otros les gusta hacer porque hace que el formulario parpadee en algunos casos. Y en algunos casos también lo hace esto. Usando this.Update, no he tenido ningún problema de parpadeo:
private bool mouseDown;
private Point lastLocation;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
mouseDown = true;
lastLocation = e.Location;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if(mouseDown)
{
this.Location = new Point(
(this.Location.X - lastLocation.X) + e.X, (this.Location.Y - lastLocation.Y) + e.Y);
this.Update();
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
mouseDown = false;
}
Otra forma más sencilla de hacer lo mismo.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// set this.FormBorderStyle to None here if needed
// if set to none, make sure you have a way to close the form!
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_NCHITTEST)
m.Result = (IntPtr)(HT_CAPTION);
}
private const int WM_NCHITTEST = 0x84;
private const int HT_CLIENT = 0x1;
private const int HT_CAPTION = 0x2;
}
utilice MouseDown, MouseMove y MouseUp. Puede establecer una bandera de variable para eso. Tengo una muestra, pero creo que debes revisarla.
Estoy codificando la acción del mouse en un panel. Una vez que haga clic en el panel, su formulario se moverá con él.
//Global variables;
private bool _dragging = false;
private Point _offset;
private Point _start_point=new Point(0,0);
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
_dragging = true; // _dragging is your variable flag
_start_point = new Point(e.X, e.Y);
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
_dragging = false;
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if(_dragging)
{
Point p = PointToScreen(e.Location);
Location = new Point(p.X - this._start_point.X,p.Y - this._start_point.Y);
}
}
Solo WPF
no tengo el código exacto a mano, pero en un proyecto reciente creo que usé el evento MouseDown y simplemente puse esto:
frmBorderless.DragMove();
Esto está probado y es fácil de entender.
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case 0x84:
base.WndProc(ref m);
if((int)m.Result == 0x1)
m.Result = (IntPtr)0x2;
return;
}
base.WndProc(ref m);
}
WM_NCHITTEST
disfrazado.
No hay propiedad que puedas voltear para que esto suceda por arte de magia. Mire los eventos del formulario y se vuelve bastante trivial implementar esto configurando this.Top
y this.Left
. Específicamente usted quiere mirar MouseDown
, MouseUp
y MouseMove
.
public Point mouseLocation;
private void frmInstallDevice_MouseDown(object sender, MouseEventArgs e)
{
mouseLocation = new Point(-e.X, -e.Y);
}
private void frmInstallDevice_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Point mousePos = Control.MousePosition;
mousePos.Offset(mouseLocation.X, mouseLocation.Y);
Location = mousePos;
}
}
esto puede resolver tu problema ...
Este fragmento de código del enlace anterior funcionó en mi caso :)
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
this.Capture = false;
Message msg = Message.Create(this.Handle, 0XA1, new IntPtr(2), IntPtr.Zero);
this.WndProc(ref msg);
}
}
La mejor forma que he encontrado (modificado por supuesto)
// This adds the event handler for the control
private void AddDrag(Control Control) { Control.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DragForm_MouseDown); }
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();
private void DragForm_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
// Checks if Y = 0, if so maximize the form
if (this.Location.Y == 0) { this.WindowState = FormWindowState.Maximized; }
}
}
Para aplicar arrastre a un control, simplemente inserte esto después de InitializeComponent ()
AddDrag(NameOfControl);
Funcionó para mí.
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
_mouseLoc = e.Location;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
int dx = e.Location.X - _mouseLoc.X;
int dy = e.Location.Y - _mouseLoc.Y;
this.Location = new Point(this.Location.X + dx, this.Location.Y + dy);
}
}
Para .NET Framework 4,
Puede usar this.DragMove()
para el MouseDown
evento del componente (mainLayout en este ejemplo) que está usando para arrastrar.
private void mainLayout_MouseDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}
La forma más sencilla es:
Primero cree una etiqueta llamada label1. Vaya a los eventos de label1> eventos del mouse> Label1_Mouse Move y escriba estos:
if (e.Button == MouseButtons.Left){
Left += e.X;
Top += e.Y;`
}
Estaba tratando de hacer que un formulario de ventanas sin bordes se pudiera mover y que contuviera un control WPF Element Host y un control de usuario WPF.
Terminé con un panel de pila llamado StackPanel en mi control de usuario de WPF, que parecía lo lógico para intentar hacer clic para mover. Probar el código de junmats funcionó cuando moví el mouse lentamente, pero si lo movía más rápido, el mouse se saldría del formulario y el formulario se atascaría en algún lugar a la mitad del movimiento.
Esto mejoró su respuesta para mi situación usando CaptureMouse y ReleaseCaptureMouse y ahora el mouse no se mueve fuera del formulario mientras lo muevo, incluso si lo muevo rápidamente.
private void StackPanel_MouseDown(object sender, MouseButtonEventArgs e)
{
_start_point = e.GetPosition(this);
StackPanel.CaptureMouse();
}
private void StackPanel_MouseUp(object sender, MouseButtonEventArgs e)
{
StackPanel.ReleaseMouseCapture();
}
private void StackPanel_MouseMove(object sender, MouseEventArgs e)
{
if (StackPanel.IsMouseCaptured)
{
var p = _form.GetMousePositionWindowsForms();
_form.Location = new System.Drawing.Point((int)(p.X - this._start_point.X), (int)(p.Y - this._start_point.Y));
}
}
//Global variables;
private Point _start_point = new Point(0, 0);
Dado que algunas respuestas no permiten que los controles secundarios se puedan arrastrar, he creado una pequeña clase de ayuda. Debe pasar el formulario de nivel superior. Puede hacerse más genérico si se desea.
class MouseDragger
{
private readonly Form _form;
private Point _mouseDown;
protected void OnMouseDown(object sender, MouseEventArgs e)
{
_mouseDown = e.Location;
}
protected void OnMouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
int dx = e.Location.X - _mouseDown.X;
int dy = e.Location.Y - _mouseDown.Y;
_form.Location = new Point(_form.Location.X + dx, _form.Location.Y + dy);
}
}
public MouseDragger(Form form)
{
_form = form;
MakeDraggable(_form);
}
private void MakeDraggable(Control control)
{
var type = control.GetType();
if (typeof(Button).IsAssignableFrom(type))
{
return;
}
control.MouseDown += OnMouseDown;
control.MouseMove += OnMouseMove;
foreach (Control child in control.Controls)
{
MakeDraggable(child);
}
}
}
Además, si necesita hacer DoubleClick y hacer que su formulario sea más grande o más pequeño, puede usar la Primera respuesta, crear una variable int global, agregar 1 cada vez que el usuario haga clic en el componente que usa para arrastrar. Si, variable == 2
entonces haz tu forma más grande / más pequeña. También use un temporizador por cada medio segundo o un segundo para hacer su variable = 0
;
Agregar un MouseLeftButtonDown
controlador de eventos a MainWindow funcionó para mí.
En el caso de que la función de evento se genere automáticamente, agregue el siguiente código:
base.OnMouseLeftButtonDown(e);
this.DragMove();
Estoy expandiendo la solución de jay_t55 con un método más ToolStrip1_MouseLeave
que maneja el evento de que el mouse se mueva rápidamente y abandone la región.
private bool mouseDown;
private Point lastLocation;
private void ToolStrip1_MouseDown(object sender, MouseEventArgs e) {
mouseDown = true;
lastLocation = e.Location;
}
private void ToolStrip1_MouseMove(object sender, MouseEventArgs e) {
if (mouseDown) {
this.Location = new Point(
(this.Location.X - lastLocation.X) + e.X, (this.Location.Y - lastLocation.Y) + e.Y);
this.Update();
}
}
private void ToolStrip1_MouseUp(object sender, MouseEventArgs e) {
mouseDown = false;
}
private void ToolStrip1_MouseLeave(object sender, EventArgs e) {
mouseDown = false;
}
Probé lo siguiente y listo, ¡mi ventana transparente ya no estaba congelada en su lugar, pero se podía mover! (deseche todas esas otras soluciones complejas anteriores ...)
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
// Begin dragging the window
this.DragMove();
}
Formulario 1(): new Moveable(control1, control2, control3);
Clase:
using System;
using System.Windows.Forms;
class Moveable
{
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();
public Moveable(params Control[] controls)
{
foreach (var ctrl in controls)
{
ctrl.MouseDown += (s, e) =>
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(ctrl.FindForm().Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
// Checks if Y = 0, if so maximize the form
if (ctrl.FindForm().Location.Y == 0) { ctrl.FindForm().WindowState = FormWindowState.Maximized; }
}
};
}
}
}
[DllImport("user32.DLL", EntryPoint = "ReleaseCapture")]
private extern static void ReleaseCapture();
[DllImport("user32.DLL", EntryPoint = "SendMessage")]
private extern static void SendMessage(System.IntPtr hWnd, int Msg, int wParam, int lParam);
private void panelTitleBar_MouseDown(object sender, MouseEventArgs e)
{
ReleaseCapture();
SendMessage(this.Handle, 0x112, 0xf012, 0);
}