从 TabControl 拖动时表单显示对话框问题



我已经实现了选项卡控件拖放。其中,当我单击选项卡控件并拖动一个新表单时,将打开一个包含选项卡页面数据的新表单。

问题是如果我保持形式。显示()。窗体显示拖动外观并随鼠标移动。但是,如果我使用表单。ShowDialog() 然后表单只是打开,拖拽效果不会发生。

在这种情况下,我只能在单击表单标题并再次拖动时拖动。我在下面写了相同的代码。

   protected override void WndProc(ref Message m)
    {
        if (m.Msg == NativeMethods.WM_MOVING)
        {
            DockUndockTabpage(m);
        }
        base.WndProc(ref m);
        switch (m.Msg)
        {
            case NativeMethods.WM_MOUSEMOVE:
                if (m.WParam.ToInt32() == 1)
                {
                    if (!captured)
                    {
                        Point pt = tabControl.PointToScreen((Cursor.Position));
                        Point newPosition = new Point(pt.X - dragOffset.X, pt.Y - dragOffset.Y);
                        this.Location = newPosition;
                    }
                    NativeMethods.RECT rc = new NativeMethods.RECT(this.Bounds);
                    IntPtr lParam = Marshal.AllocHGlobal(Marshal.SizeOf(rc));
                    Marshal.StructureToPtr(rc, lParam, true);
                    NativeMethods.SendMessage(this.Handle, NativeMethods.WM_MOVING, IntPtr.Zero, lParam);
                    Marshal.FreeHGlobal(lParam);
                }
                break;
            case NativeMethods.WM_SETCURSOR:
                captured = true;
                break;
            default:
                break;
        }
    }

有两种方法可以分别执行停靠和取消停靠,从原始窗体到和从原始窗体开始。

private void DockToTab()
    {
        if (!tabControl.TabPages.Contains(tabPageToInsert))
        {
            tabControl.TabPages.Insert(tabID, tabPageToInsert);
            tabControl.SelectedTab = tabPageToInsert;
            tabControl.Capture = true;
            this.Close();
        }
    }
private  static void UnDockFromTab()
    {
        if (formToShow.Visible || formToShow.IsDisposed)
            return;
        formToShow.tabControl.TabPages.Remove(formToShow.tabPageToInsert);
        formToShow.Capture = true;
        formToShow.ShowDialog();
    }

金尔迪帮助。

我注意到我对这种UI的反对意见,它非常难以发现。 无论如何,一些代码可以使其工作。 您必须做的基本事情是检测用户开始在 TabControl 上拖动鼠标。 检测到后,您可以即时创建表单。 将其放在与选项卡相同的位置,使其看起来像是从选项卡本身拖动的。 然后,您需要一个技巧来说服表单它正在被其标题栏拖动,您可以通过发布WM_NCLBUTTONDOWN消息来实现。 这效果很好:

    private Point TabMouseDownPos;
    private void tabControl1_MouseDown(object sender, MouseEventArgs e) {
        TabMouseDownPos = e.Location;
    }
    private void tabControl1_MouseMove(object sender, MouseEventArgs e) {
        // Detect start of drag
        if (e.Button != System.Windows.Forms.MouseButtons.Left) return;
        int dx = e.X - TabMouseDownPos.X;
        int dy = e.Y - TabMouseDownPos.Y;
        if (Math.Abs(dx) >= SystemInformation.DoubleClickSize.Width ||
            Math.Abs(dy) >= SystemInformation.DoubleClickSize.Height) {
            // Start drag, create the form at the same position as the tab
            Form form = CreateTabForm();
            form.StartPosition = FormStartPosition.Manual;
            var tabpos = tabControl1.GetTabRect(tabControl1.SelectedIndex);
            form.Location = tabControl1.PointToScreen(new Point(tabpos.Left + dx, tabpos.Top + dy));
            // Juggle the mouse so it now starts dragging the form
            tabControl1.Capture = false;
            PostMessage(form.Handle, WM_NCLBUTTONDOWN, (IntPtr)2, IntPtr.Zero);
            form.ShowDialog();          
        }
    }
    private Form CreateTabForm() {
        // Return form object that matches tabControl1.SelectedIndex
        //...
        return new Form2();
    }
    private const int WM_NCLBUTTONDOWN = 0x00a1;
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    private static extern IntPtr PostMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);

使用 CreateTabForm() 方法创建与 tabControl.SelectedIndex 属性值匹配的窗体实例。

最新更新