【问题标题】:Handle DragDrop outside of control - DragEnd event?在控制之外处理 DragDrop - DragEnd 事件?
【发布时间】:2019-08-15 15:04:46
【问题描述】:

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

目前 WinForm 应用程序只有一个主要的 TabControl,而我正在查看与 DoDragDrop() 相关的事件,但它们似乎只有在你有两个 TabControls 并在这两个周围移动 TabPages 时才有效。

有没有办法让它只使用一个TabControl?意思是,如果您将DropTabPageTabControl 中取出,那么它将创建一个新的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 时都会创建新标签。

【问题讨论】:

  • this开头。
  • 还有this
  • @Alex 使 TabControl 可拖动是最简单的部分。我想要做的是让它什么都不放,以创建第二个控件。创建第二个控件后,拖放是直接的。实际创建第二个控件的操作是我想要找出的。

标签: c# winforms drag-and-drop


【解决方案1】:

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

您可以依靠QueryContinueDrag 并检查操作是否为Drop,然后检查鼠标位置,例如,如果它不在您的控件内,只需创建另一个窗口并将选定的选项卡添加到选项卡控件中新窗口。

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 事件中设置一个静态属性来跟踪放置目标。如果放置目标具有值,则意味着您正在放置派生选项卡控件,否则意味着您正在放置外部。然后,您的所有自定义选项卡控件都可以轻松启用拖放功能。

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

  • 添加选项卡时,可以在目标中选中的选项卡或光标下的选项卡之前/之后插入。

【讨论】:

  • 你想要实现的,已经在一些库中实现了,比如DockPanel Suite。所以你可能想看看它的source code 或试一试。
  • 您可以看到我在pastebin 上添加的此示例中的一些增强功能。将示例复制并粘贴到项目的文件中,构建项目,然后从工具箱中,将MyTabControl 的实例添加到表单并运行它。
  • 谢谢!我一直在看QueryContinueDrag,但文档让它看起来像是可以控制下一个拖动事件。我从没想过实际上将它包含在方法中。
猜你喜欢
  • 2011-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多