从 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