6

我已经构建了一个自定义控件,我希望人们可以单击并拖动我的控件,就像他们在窗口标题栏上拖动一样。做这个的最好方式是什么?

到目前为止,我一直未能成功利用鼠标向下、向上和移动事件来破译何时需要移动窗口。

4

3 回答 3

11

除了我的其他答案之外,您还可以在这样的控件中手动执行此操作:

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

编辑:经过测试和修复 - 这现在确实有效。

于 2010-03-05T03:50:32.573 回答
5

最有效的方法是处理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
}

但是,如果此时有控件,我认为不会发送消息。

于 2010-03-05T03:33:03.440 回答
3

如果你想让表单的一部分表现得像标题,WM_NCHITTEST那么 SL​​aks 给出的技巧就是要走的路。但是如果你想让一个子窗口能够拖动窗体,还有另一种方法。

基本上,如果您使用 MOUSE_MOVE 命令 id 向 DefWindowProc 发送 WM_SYSCOMMAND 消息,那么 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.
  }
于 2010-03-05T04:48:15.040 回答