65.9K
CodeProject 正在变化。 阅读更多。
Home

改进的拖放实现,具有完全的位置控制

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.58/5 (20投票s)

2007年6月24日

6分钟阅读

viewsIcon

80379

downloadIcon

2838

如果您需要在自己的类中使用拖放操作时获得更高级的控制,那么本文是一个很好的起点。用户可以更自由地控制对象的定位。理解本文内容的最佳方法是下载并运行演示。

引言

这是一个演示应用程序,展示了如何实现一个拖放解决方案,该方案为您提供更多的定位控制。只要您将对象移动到其容器内,就不需要执行真正的拖放操作。您只需更改其位置。此应用程序显示了如何自动切换这两种方法。

为了进行精确的定位,您可能希望在移动对象时看到对象的轮廓。此应用程序也显示了这一点。您还可以使用箭头键移动对象。为了对齐对象,您很可能需要一个网格进行吸附。这也被包含在应用程序中。为了增加此演示的价值,拖放对象还可以通过角落抓手进行调整大小。

这一切都已在 Visual Studio 2005 和 .NET 2.0 框架中完成。

背景

我开始创建一个应用程序,其中包含一个工具箱,里面有不同的对象,用户可以将它们拖放到窗体或其他容器对象上。起初我只尝试使用真正的拖放,但这种方法给了我一个非常粗糙简单的应用程序。需要更高级的功能才能让用户获得更多控制。

如何开始

  1. 下载最新的 SmartDragDrop 演示应用程序,以了解它的作用!
  2. 下载最新的 SmartDragDrop 源项目,以查看实现,并将您喜欢的代码部分复制到您自己的项目中。
  3. 阅读此页面末尾的消息!

使用代码

Screenshot - SmartDragDrop.jpg

该项目包含四个类:MyForm.csMyUserControl.csOutline.cs 和标准的 Program.csProgram 类创建了两个 MyForm 窗口作为游乐场。然后创建一个 MyUserControl 作为拖放对象。它被放置在第二个窗口中。当我们移动或调整拖放对象大小时,将使用 Outline 对象来显示鼠标移动。

MyForm 类实现了

  • 接受 MyUserControl 对象的拖放。首先,我们必须将 Form 属性 AllowDrop 设置为 true,以便我们的 Form 能够接受任何拖放对象。然后,我们添加 DragEnterDragDrop 事件。DragEnter 事件用于拒绝我们不支持的对象。DragDrop 事件用于在正确的位置重新创建并添加我们的 MyUserControl 对象。
  • 需要一个网格来精确地定位 MyUserControl 对象。如果 Form 上的网格复选框被选中,DisplayOrHideGrid 方法将在我们的 MyForm 窗口上绘制一个网格。Graphics 类用于在我们的 Form 上绘制网格。公共方法 SnapToGrid 在本地以及由 MyUserControl 类使用,以重新计算吸附到网格的位置。

MyUserControl 类实现了

  • 通过角落抓手调整大小:UserControl 没有像 Form 的 SizeGripStyle 那样的调整大小功能。要实现此功能,可以使用带有 PictureBox 的透明角落抓手图像。MouseDownMouseUp 事件用于简单地调整我们的 MyUserControl 对象的大小。
  • 移动时进行假拖放和真拖放:通过假拖放,我的意思是简单地使用 MouseDownMouseUp 事件来移动我们的 MyUserControl 对象。IsCursorInside 方法在 MouseMove 事件中使用,以检查鼠标光标是否离开我们的 MyForm。如果是,则启动真正的拖放操作。公共属性 MouseDownStartPointMyForm 中使用,以在完成拖放操作时保留鼠标指针的位置。也就是说,如果我从中心开始拖动,我希望在放下对象时在中心找到光标。
  • 通过箭头键进行高分辨率移动:为了使用户能够对齐对象,箭头键将使 MyUserControl 对象移动一个像素。我们需要重写 IsInputKey 事件,以便能够捕获 UserControl 对象中的箭头键事件。
  • 移动或调整大小时显示自身轮廓:Outline.cs 中的静态方法创建了一个在移动时使用的光标对象。使用一个透明的窗体。这使用户在移动或调整大小时获得更好的控制。
  • 吸附到父网格的可能性:每当移动 MyUserControl 对象时(不是放下),就会调用 MyForm 方法 SnapToGrid 来重新计算吸附到网格的位置。

Outline 类实现了

  • 用作光标的透明窗体:此类中用于操作 Outline 对象的所有方法都是静态的。这使得使用简单,并确保只使用一个光标对象。由于我们只有一个鼠标,一次只能执行一次移动或调整大小,因此不需要创建多个光标对象。与之前创建真正光标的解决方案相比,此技术节省了大量内存和 CPU。

讨论

这一切都作为一个示例应用程序实现。如何在任何应用程序中使其有用?我们可以继承我们的两个类 MyFormMyUserControl。缺点是,那么我们将只能使用 Form 作为容器,使用 UserControl 作为拖放对象。我们也可以创建一个特殊的 SmartDragDrop 类在 UserControl 类中使用。但是,也很难使其成为一个干净的解决方案。

此外,如何处理鼠标事件?我们的 MyFormMyUserControl 类之间有一些不太好的联系。子级不应该知道其父级,但在调用 SnapToGrid 时就是这种情况。如何改进?也许使用接口?

请改进代码并分享您的想法!

关注点

本文讨论了这些问题

  • 如何拖放用户定义的类
  • 如何在移动或调整大小时显示某些对象的轮廓
  • 如何为 UserControl 类创建调整大小抓手
  • 如何在 Form 上绘制网格

历史

  • 2007-06-24:提交本文和代码 1.0。请不要忘记为此文章投票;我真的很想知道和学习!
  • 2007-07-13:已纠正错误:在 MyUserControl.cs 的事件方法 userControl_MouseUp 中,现在取消了 MouseMove 事件的注册。已改进光标对象的释放。
  • 2007-07-16:新的光标解决方案:我们现在使用一个透明的窗体 Outline.cs,而不是创建一个真正的光标对象。这节省了大量内存和 CPU,特别是移动大型对象时。现在在调整大小时也使用光标。以前的版本 1.1 没有错误。您可以在此处获取它;在某些应用程序中,它可能与此一样好。
© . All rights reserved.