Risposte:
Questo articolo su CodeProject descrive in dettaglio una tecnica. Fondamentalmente si riduce 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);
}
}
Questo essenzialmente fa esattamente lo stesso che afferrare la barra del titolo di una finestra, dal punto di vista del gestore delle finestre.
Form1_MouseDown
non è assegnato MouseDown
all'evento effettivo di Form1
.
this.MouseDown += ...
alla Main()
funzione per il modulo
Non rendiamo le cose più difficili di quanto dovrebbero essere. Mi sono imbattuto in così tanti frammenti di codice che ti consentono di trascinare un modulo (o un altro controllo). E molti di loro hanno i loro svantaggi / effetti collaterali. Soprattutto quelli in cui inducono Windows a pensare che un controllo su un modulo sia il modulo effettivo.
Detto questo, ecco il mio frammento. Io lo uso per tutto il tempo. Vorrei anche notare che non dovresti usare this.Invalidate (); come ad altri piace fare perché in alcuni casi provoca lo sfarfallio del modulo. E in alcuni casi lo fa anche questo. Utilizzando this.Update, non ho avuto problemi di sfarfallio:
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;
}
Un altro modo più semplice per fare la stessa cosa.
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;
}
usa MouseDown, MouseMove e MouseUp. Puoi impostare un flag variabile per questo. Ho un campione, ma penso che tu debba rivedere.
Sto codificando l'azione del mouse su un pannello. Dopo aver fatto clic sul pannello, il modulo si sposterà con esso.
//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
non ho il codice esatto a portata di mano, ma in un progetto recente penso di aver usato l'evento MouseDown e semplicemente messo questo:
frmBorderless.DragMove();
Questo è testato e facile da capire.
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
sotto mentite spoglie.
Non ci sono proprietà che puoi capovolgere per farlo accadere magicamente. Guarda gli eventi per il modulo e diventa abbastanza banale implementarlo impostando this.Top
e this.Left
. In particolare ti consigliamo di guardare MouseDown
, MouseUp
e 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;
}
}
questo può risolvere il tuo problema ....
Questo bit di codice dal link sopra ha fatto il trucco nel mio 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);
}
}
Il modo migliore che ho trovato (modificato ovviamente)
// 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; }
}
}
Per applicare il trascinamento a un controllo è sufficiente inserirlo dopo InitializeComponent ()
AddDrag(NameOfControl);
Ha funzionato per me.
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);
}
}
Per .NET Framework 4,
Puoi usare this.DragMove()
per l' MouseDown
evento del componente (mainLayout in questo esempio) che stai usando per trascinare.
private void mainLayout_MouseDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}
Il modo più semplice è:
Per prima cosa crea un'etichetta denominata label1. Vai agli eventi di label1> eventi del mouse> Label1_Mouse Move e scrivi questi:
if (e.Button == MouseButtons.Left){
Left += e.X;
Top += e.Y;`
}
Stavo cercando di rendere mobile una finestra senza bordi che conteneva un controllo WPF Element Host e un controllo WPF User.
Ho finito con un pannello dello stack chiamato StackPanel nel mio controllo utente WPF che sembrava la cosa logica su cui provare a fare clic per spostarmi. Il codice di Junmats ha funzionato quando ho spostato il mouse lentamente, ma se ho spostato il mouse più velocemente, il mouse si spostava fuori dal modulo e il modulo sarebbe rimasto bloccato da qualche parte a metà movimento.
Questo ha migliorato la sua risposta per la mia situazione usando CaptureMouse e ReleaseCaptureMouse e ora il mouse non si sposta dal modulo mentre lo sposta anche se lo sposto rapidamente.
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);
Poiché alcune risposte non consentono di trascinare i controlli figlio, ho creato una piccola classe di supporto. Dovrebbe essere passato il modulo di primo livello. Può essere reso più generico se lo si desidera.
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);
}
}
}
Inoltre, se hai bisogno di DoubleClick e rendere il tuo modulo più grande / più piccolo, puoi utilizzare la prima risposta, creare una variabile globale int, aggiungere 1 ogni volta che l'utente fa clic sul componente che utilizzi per il trascinamento. Se variable == 2
poi rendi il tuo modulo più grande / più piccolo. Usa anche un timer ogni mezzo secondo o un secondo per fare il tuo variable = 0
;
L'aggiunta di un MouseLeftButtonDown
gestore di eventi alla MainWindow ha funzionato per me.
Nella funzione evento che viene generata automaticamente, aggiungi il codice seguente:
base.OnMouseLeftButtonDown(e);
this.DragMove();
Sto espandendo la soluzione da jay_t55 con un altro metodo ToolStrip1_MouseLeave
che gestisce l'evento in cui il mouse si sposta rapidamente e lascia la regione.
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;
}
Ho provato quanto segue e presto changeo, la mia finestra trasparente non era più bloccata ma poteva essere spostata !! (butta via tutte quelle altre soluzioni complesse sopra ...)
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
// Begin dragging the window
this.DragMove();
}
Form1 (): new Moveable(control1, control2, control3);
Classe:
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);
}