Элемент управления, имитирующий перетаскивание строки заголовка окна - PullRequest
6 голосов
/ 05 марта 2010

Я создал пользовательский элемент управления, и я бы хотел, чтобы люди нажимали и перетаскивали его, как если бы они перетаскивали строку заголовка окна. Каков наилучший способ сделать это?

До сих пор мне не удавалось задействовать мышь вниз, вверх и перемещать события для расшифровки, когда необходимо переместить окно.

Ответы [ 3 ]

10 голосов
/ 05 марта 2010

В дополнение к моему другому ответу вы можете сделать это вручную в элементе управления следующим образом:

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;
    }
}

РЕДАКТИРОВАТЬ : протестировано и исправлено - теперь это действительно работает.

5 голосов
/ 05 марта 2010

Самый эффективный способ сделать это - обработать уведомление 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
}

Тем не менее, я не думаю, что сообщение будет отправлено, если в этот момент будет элемент управления.

3 голосов
/ 05 марта 2010

Если вы хотите, чтобы часть формы велась как заголовок, то способ 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.
  }
...