Вопрос

I have implemented Tab Control drag drop.Where, when i click on Tab Control and drag a new form is opened with the data of Tabpage.

The problem is if i keep form.Show().The form shows drag appearance and moves with the mouse. However if i use form.ShowDialog() then form simply opens and drag effect does not take place.

In such case i am able to drag only when i click on form header and drag it again. I have written below code for the same.

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

There are two methods that do docking and Undocking, To and from the original form respectively.

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 help.

Это было полезно?

Решение

I note my objection against this kind of UI, it is very undiscoverable. Some code to make it work anyway. Basic things you have to do is to detect the user starting to drag the mouse on the TabControl. Once detected, you can then create the form on-the-fly. Put it at the same location as the tab so it looks like it was dragged from the tab itself. You then need a trick to convince the form that it is being dragged by its caption bar, you do so by posting the WM_NCLBUTTONDOWN message. This worked well:

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

Work on the CreateTabForm() method to create an instance of the form that matches the tabControl.SelectedIndex property value.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top