从 TabControl 拖动时出现表单 ShowDialog 问题

Posted

技术标签:

【中文标题】从 TabControl 拖动时出现表单 ShowDialog 问题【英文标题】:Form ShowDialog Issue When Drag From TabControl 【发布时间】:2014-01-11 13:00:01 【问题描述】:

我已经实现了选项卡控件拖放。在哪里,当我单击选项卡控件并拖动时,会打开一个带有选项卡页数据的新表单。

问题是如果我保留 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;
        
    

停靠和取消停靠有两种方法,分别是To和from原始表单。

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,只需在标签页中添加一个查看按钮即可。 @HansPassant 我刚刚给出了取消停靠和停靠表单的代码的 sn-p。当用户单击 TabPage Header 并拖动它时,会打开一个新表单。我在 Tabpage Header 上添加了图像表示此标签页是可拖动的。 我需要知道为什么 Drag 适用于 Show() 而不适用于 ShowDialog()。如果需要,我可以让项目获得更多想法。 ShowDialog() 方法锁定所有事件。如果您不想停止其他表单事件,则必须使用 Show() 方法。 @nercan Ohh 可能这就是我无法以所需方式拖动表单的原因,因为没有正确调用内部事件..? 【参考方案1】:

我注意到我对这种 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 属性值匹配的表单实例。

【讨论】:

Pasant。这对我有用。非常感谢先生。我被困了几个小时来寻找解决方案.. 我有一个问题或者相当怀疑。如果我们使用 PostMessage 会导致任何问题。就像我的情况一样。它解决了拖动问题。但它会在某些方面影响任何其他事件。请抛出这方面的一些知识。谢谢。

以上是关于从 TabControl 拖动时出现表单 ShowDialog 问题的主要内容,如果未能解决你的问题,请参考以下文章

尝试从 JSP 表单调用 servlet 时出现 404 错误

WPF 拖动时出现 Invalid FORMATETC structure

WPF 控件库——可拖动选项卡的TabControl

解决YII提交POST表单出现400错误,以及ajax post请求时出现400问题

当我在可拖动中使用轴属性时出现可放置问题

如果稍微向下滚动,在画布上拖动文本时出现问题