在控制之外处理 DragDrop - DragEnd 事件?

Handle DragDrop outside of control - DragEnd event?

我正在尝试在 WinForm 应用程序中模仿 Web 浏览器的行为,您可以在其中将选项卡拖入和拖出浏览器,并在将选项卡放到不存在的某个位置时创建它的另一个实例选项卡。

目前 WinForm 应用程序只有一个主要 TabControl,我正在查看 DoDragDrop() 相关事件,但它们似乎只有在您有两个 TabControls 和移动 TabPages 围绕那两个。

有没有办法让它只与一个 TabControl 一起工作?意思是,如果你从 TabControlDrop 一个 TabPage 那么它会创建一个新的 TabControl 其中包含 TabPage?

我只能想到使用:

private void TabControl_DragLeave(object sender, EventArgs e)
{
    Form newInstance = new Form();
    TabControl newTabControl = new TabControl();

    newInstance.Controls.Add(newTabControl);
    newTabControl.TabPages.Add(sender as TabPage);
    newInstance.Show();
}

但这很粗糙,每次离开 TabControl 时都会创建新选项卡。

看来您正在寻找一个在放置结束时引发的事件,无论是在您的控制范围内还是在您的控制范围之外。

您可以依赖 QueryContinueDrag 并检查操作是否为 Drop,然后检查鼠标位置,例如,如果它不在您的控制范围内,则只需创建另一个 window 并将所选选项卡添加到新 window.

内的选项卡控件中
private void tabControl1_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        tabControl1.DoDragDrop(tabControl1.SelectedTab, DragDropEffects.All);
    }
}
private void tabControl1_DragOver(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(typeof(TabPage)))
        e.Effect = DragDropEffects.Move;
}
private void tabControl1_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
{
    if (e.Action == DragAction.Drop)
    {
        var tabPage = tabControl1.SelectedTab;
        if (!tabControl1.RectangleToScreen(tabControl1.Bounds).Contains(Cursor.Position))
        {
            var form = new Form();
            form.Text = tabPage.Text;
            var tabControl = new TabControl();
            tabControl.TabPages.Add(tabPage);
            tabControl.Dock = DockStyle.Fill;
            form.Controls.Add(tabControl);
            form.FormBorderStyle = FormBorderStyle.SizableToolWindow;
            form.StartPosition = FormStartPosition.Manual;
            form.Location = new Point(Cursor.Position.X - form.Width / 2,
                Cursor.Position.Y - SystemInformation.CaptionHeight / 2);
            form.Show();
            e.Action = DragAction.Cancel;

            //You can comment tabControl.TabPages.Add 
            //Then set e.Action = DragAction.Continue
            //Then the DragDrop event will raise and add the tab there.
        }
    }
}
private void tabControl1_DragDrop(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(typeof(TabPage)))
    {
        var tabPage = (TabPage)e.Data.GetData(typeof(TabPage));
        tabControl1.TabPages.Remove(tabPage);
        tabControl1.TabPages.Add(tabPage);
    }
}

对于更高级的场景和增强代码:

  • 开始拖动时,鼠标至少拖动到指定的点数,例如16个点数,即可开始拖动。这很容易计算。将 p1 作为鼠标按下点,将 p2 作为鼠标移动点,将 d 作为拖动阈值。开始拖动以防万一 (p1.X-p2.X)*(p1.X-p2.X) + (p1.Y-p2.Y)*(p1.Y-p2.Y) > d*d.

  • 您可以使用 GiveFeedback 事件禁用鼠标的默认光标,而是在拖动时显示更合适的光标,很容易通过 e.UseDefaultCursors = false; 和设置 Cursor.Current = Cursors.SizeAll;例如。

  • 您可以封装逻辑并将其放在派生的TabControl中。然后在 DragEnterDragLeave 事件中设置静态 属性 用于跟踪放置目标。如果 drop-target 有值,则表示您正在派生的选项卡控件上放置,否则意味着您正在放置在外部。然后可以轻松地为所有自定义选项卡控件启用拖放功能。

  • 您可以在拖放后关闭工具表单,以防表单不包含任何其他选项卡。

  • 添加标签时,可以将其插入before/after选中的标签或目标光标下的标签。