Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 控件,该控件模拟拖动窗口标题栏_C#_Winforms_Controls_Drag - Fatal编程技术网

C# 控件,该控件模拟拖动窗口标题栏

C# 控件,该控件模拟拖动窗口标题栏,c#,winforms,controls,drag,C#,Winforms,Controls,Drag,我已经构建了一个自定义控件,我希望允许人们在我的控件上单击和拖动,就像他们在窗口标题栏上拖动一样。最好的方法是什么 到目前为止,我还没有成功地利用鼠标下、上和移动事件来破译何时需要移动窗口。最有效的方法是处理通知 重写表单的WndProc方法并添加以下代码: if (m.Msg == 0x0084) { //WM_NCHITTEST var point = new Point((int)m.LParam); if(someRect.Contains(Po

我已经构建了一个自定义控件,我希望允许人们在我的控件上单击和拖动,就像他们在窗口标题栏上拖动一样。最好的方法是什么


到目前为止,我还没有成功地利用鼠标下、上和移动事件来破译何时需要移动窗口。

最有效的方法是处理通知

重写表单的
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
}

但是,我认为如果在该点上有控件,则不会发送消息。

除了我的另一个答案之外,您可以在如下控件中手动执行此操作:

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

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

如果你想让表单的一部分表现得像标题一样,SLaks提供的
WM\u NCHITTEST
技巧就是一条出路。但是,如果您想使子窗口能够拖动窗体,还有另一种方法

基本上,如果使用鼠标移动命令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.
  }

我很好奇。。。你能详细说明一下吗?这到底是怎么做的呢?@echo:它告诉Windows窗体的那部分是标题栏,可以拖动。请注意,这也将允许通过双击该部分使表单最大化。哈,巧妙的技巧,我以前从未见过这个。我花了一分钟才弄明白这到底是怎么回事!这对我来说很有效,但我必须更改ReleaseCapture以避免出现任何争论。看见