Я создал пользовательский элемент управления, и я хотел бы позволить людям перетаскивать на моем управлении так же, как если бы они тормозили панель заголовка окна. Что лучший способ состоит в том, чтобы сделать это?
До сих пор я был неудачен при усилении мыши вниз, и событий перемещения для дешифровки, когда окно должно быть перемещено.
В дополнение к моему другому ответу вы можете сделать это вручную в элементе управления следующим образом:
Point dragOffset;
protected override void OnMouseDown(MouseEventArgs e) {
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left) {
dragOffset = this.PointToScreen(e.Location);
var formLocation = FindForm().Location;
dragOffset.X -= formLocation.X;
dragOffset.Y -= formLocation.Y;
}
}
protected override void OnMouseMove(MouseEventArgs e) {
base.OnMouseMove(e);
if (e.Button == MouseButtons.Left) {
Point newLocation = this.PointToScreen(e.Location);
newLocation.X -= dragOffset.X;
newLocation.Y -= dragOffset.Y;
FindForm().Location = newLocation;
}
}
РЕДАКТИРОВАТЬ : Проверено и исправлено - теперь это действительно работает.
Наиболее эффективный способ сделать это - обработать уведомление WM_NCHITTEST
.
Переопределите метод формы WndProc
и добавьте следующий код:
if (m.Msg == 0x0084) { //WM_NCHITTEST
var point = new Point((int)m.LParam);
if(someRect.Contains(PointToClient(point))
m.Result = new IntPtr(2); //HT_CAPTION
}
Однако я не думаю, что сообщение будет отправлено, если в этот момент есть элемент управления.
Если вы хотите, чтобы часть формы вела себя как надпись, то WM_NCHITTEST
трюк, который привел SLaks - это то, что нужно. Но если вы хотите, чтобы дочернее окно могло перетаскивать форму, есть другой способ.
В основном, если вы пошлете сообщение WM_SYSCOMMAND в DefWindowProc с идентификатором команды MOUSE_MOVE, то Windows перейдет в режим перетаскивания. В принципе, именно так это делает надпись, но, устранив посредника, мы можем инициировать это перетаскивание из дочернего окна, и мы не получаем всех других поведений надписи.
public class form1 : Form
{
...
[DllImport("user32.dll")]
static extern IntPtr DefWindowProc(IntPtr hWnd, uint uMsg, UIntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
static extern bool ReleaseCapture(IntPtr hwnd);
const uint WM_SYSCOMMAND = 0x112;
const uint MOUSE_MOVE = 0xF012;
public void DragMe()
{
DefWindowProc(this.Handle, WM_SYSCOMMAND, (UIntPtr)MOUSE_MOVE, IntPtr.Zero);
}
private void button1_MouseDown(object sender, MouseEventArgs e)
{
Control ctl = sender as Control;
// when we get a buttondown message from a button control
// the button has capture, we need to release capture so
// or DragMe() won't work.
ReleaseCapture(ctl.Handle);
this.DragMe(); // put the form into mousedrag mode.
}