从TabControl拖动时表单ShowDialog问题

时间:2013-12-23 10:14:38

标签: c# winforms drag-and-drop draggable showdialog

我已经实现了Tab Control拖放。当我点击Tab Control并拖动时,会打开一个带有Tabpage数据的新表单。

问题是如果我保持form.Show()。表单显示拖动外观并随鼠标移动。 但是,如果我使用form.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();
    }

Kinldy帮助。

1 个答案:

答案 0 :(得分:1)

我注意到我对这种用户界面的反对意见,这是非常难以发现的。一些代码使其无论如何都能正常工作。您需要做的基本事情是检测用户开始在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属性值匹配的表单实例。