可拖放的TreeView控件






3.86/5 (18投票s)
2004年8月1日
4分钟阅读

317477

5542
一个内置拖放功能的树形视图。
引言
开发人员想要用树形视图实现的一种常见行为是拖放。出于某些原因,微软并没有让 .NET TreeView
控件完全轻松地实现这一点(即使在 2.0 beta 版中也没有改变)。虽然实现起来并不算太难,但最好有一个内置此功能的控件,而不是每次想在树形视图中实现拖放时都复制代码片段。
拖放主要围绕 4 个事件:OnDragDrop
、OnDragEnter
、OnDragLeave
、OnDragOver
,以及在 TreeView
控件中的 OnItemDrag
。我将不再详细介绍这些事件的调用顺序或它们的作用,您可以查阅 MSDN 文档或使用 Google。总而言之,这些事件已在此 TreeViewDragDrop
控件中实现。
控件的特性
我为我存储代码示例的网站(www.sloppycode.net,无耻的宣传)的一个管理应用程序构建了这个控件。牢记“编程是 90% 的设计”这句古老的格言,我写下了以下我希望控件实现的功能:
- 自动滚动
- 鼠标悬停在节点上时高亮目标节点
- 拖动时的自定义光标
- 拖动时的自定义幽灵图标标签
- 按 Escape 键取消拖动
- 通过
DragStart
事件阻止某些节点被拖动 - 拖动时的健全性检查(不允许父节点拖动到子节点,目标不能是源节点)
上述部分功能并未在 MSDN 中记录,但如果仔细搜索 Google 群组和网站,可能会找到。我现在将逐步介绍这些核心功能的实现。
自动滚动
这是通过 WinAPI SendMessage
调用实现的。OnDragOver
事件执行一个 SendMessage
调用(277 是常量值,我猜是 WM_SCROLL
,但我没查证)。这会根据鼠标位置向上或向下滚动树形视图。
高亮目标节点
这个实现起来相当简单,您只需在 OnDragOver
事件中更改目标节点的背景色和前景色。默认颜色基于 Windows Explorer,背景色使用系统的“高亮”颜色,前景色使用“高亮文本”颜色。我已将这些设置为控件的属性,以便用户可以随意更改。
拖动时的自定义光标
这是使用 OnGiveFeedback
事件实现的。该事件传递一个 GiveFeedbackEventArgs
类,其中包含一个 UseDefaultCursors
属性。如果我们要实现自定义光标,可以将此属性设置为 false
,并将其更改为我们想要的光标。我们还会检查是否正在进行拖动,如果不是,则将光标恢复原状。
自定义幽灵图标
这是控件中最漂亮的功能,但也可能是 bug 的最大来源。它复制了 Windows Explorer 的行为,显示正在拖动的节点,以“幽灵化”或淡化的形式,包括节点的标签和图标。我通过使用第二个表单来实现这一点,该表单被移动到鼠标所在的位置。通过控件中的属性,您可以更改显示的图像以及标签的字体。这是一个比上面提到的自定义光标更好的版本,尽管我感觉我走了一条弯路,可能有一个 Windows API 调用已经完成了这项工作——问题是我不知道是什么。如果有人知道,请告知。
按 Escape 键取消拖动
这是 Windows Explorer 树形视图的另一个标准行为,即您可以通过按 Escape 键来取消拖动。OnKeyUp
事件用于执行此操作,它会检查按下的键是否是 Escape 键,如果是,则取消拖动,并将任何被拖动的节点恢复到其原始状态。
阻止某些节点被拖动
我在控件中添加了一些自定义事件,以增加一些小的额外事件功能。其中最主要的是 DragStart
事件。在拖动开始时会触发此事件,允许您检查正在拖动的节点,并在必要时阻止拖放事件。例如,如果您在树形视图中有一个回收站,并且不希望用户随意拖动它,那么这个功能就很有用。
拖动的健全性检查
这是为了防止节点拖动到自身内部或拖动到自身而内置的。它使用 Path
属性以最快的方式进行检查。这意味着,如果您有两个相同的路径,那么它将不起作用;您可能需要构建一个派生类来解决这个问题,并通过遍历父节点并逐个检查的方式来解决。
差不多就是这样了。我重写了 WndProc
事件,它阻止了树形视图在每次更新时重绘背景,从而消除了闪烁。当您拖动一个节点时,它仍然会有一点闪烁,但这似乎是 .NET 框架控件的一个问题。我已经尝试了双缓冲,但没有成功,欢迎任何建议。
希望它对某些人有所帮助。