带自动滚动的 ReorderListView 控件
一个VB版本,增加了“ListView中的项目手动重新排序”的功能。
引言
该控件是对文章“ListView中的项目手动重新排序”中代码的扩展,作者是mav.northwind。功劳归于Mav。我只需要几个额外功能,所以就实现了它们,并将其发布出来,希望对大家有所帮助。此外,我还借鉴了Les Smith在其文章ListView Drag & Drop With Auto Scrolling in .NET (Upgraded)中讨论的自动滚动功能。
以下功能已添加到由mav.northwind开发的控件中:
- 多选项目重新排序功能
- 在重新排序时自动滚动
ListView
- 使用
DisableItemReorder
属性启用/禁用重新排序功能 - 使用
ReorderStartIndex
属性锁定列表中前(n)个项目 - 使用
InsertionLineColor
属性更改插入条的颜色
此外,我还将用于重新排序的ListView
事件处理程序移到了ListView
控件本身中,因此无需在窗体中处理任何内容。最后,由于我的项目需要在VB中完成,所以我将所有C#代码都改成了VB。
背景
有关本文的背景信息,您应该参考mav.northwind的文章“ListView中的项目手动重新排序”。还有其他解决方案,通常使用拖放事件。我喜欢这种方法,因为它很简洁,并且将拖放功能留给了处理外部项目的拖放。我还推荐Les Smith的文章“ListView Drag & Drop With Auto Scrolling in .NET (Upgraded)”,该文章讨论了相同的主题,但还解决了自动滚动功能。
Using the Code
要使用此代码,只需将自定义控件类ReorderListView
添加到您的项目中。生成控件类,然后在Windows窗体上使用ReorderListView
控件。示例代码和项目是用VS2008完成的;但是,该代码在早期版本中应该也能正常工作。
关注点
对多选项目的支持非常简单,首先将选定的项目存储到列表集合中,然后从ListView
中删除它们,最后将它们全部插入回ListView
的正确索引位置。至于自动滚动,只需使用SendMessageA
函数滚动控件即可。添加了一个计时器并处理了onTick
事件以启动SendMessage
例程,因此计时器的Interval
设置了调用SendMessage
例程的频率。当计时器的Interval
值较小时,会更频繁地调用SendMessage
,从而实现更快的滚动;当计时器的Interval
较大时,调用次数较少,滚动速度较慢。
Public Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent()
'Reduce Flicker
SetStyle(Windows.Forms.ControlStyles.OptimizedDoubleBuffer, True)
'Initialize Scrolling Timer
tmrLVScroll.Enabled = False
tmrLVScroll.Interval = 100
End Sub
#Region "Scrolling Support"
'This section handles the auto-scrolling when an item
'is dragged to the top or bottom of the list
Private Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" (ByVal hwnd As Integer, _
ByVal wMsg As Integer, ByVal wParam As Integer, _
ByRef lParam As Object) As Integer
Private Sub tmrLVScroll_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles tmrLVScroll.Tick
ScrollControl(Me, intScrollDirection)
End Sub
Private Sub ScrollControl(ByRef objControl As Control, ByRef intDirection As Integer)
Const WM_SCROLL As Integer = &H115S
SendMessage(objControl.Handle.ToInt32, WM_SCROLL, intDirection, VariantType.Null)
End Sub
#End Region
现在,只需启用计时器滚动并确定滚动方向,并在不滚动时禁用它。为了在正确的时间启用/禁用计时器,我在下面的MouseMove
事件中添加了一些代码。我使用了列表中的第一个项目而不是控件本身的顶部来确定何时应该向上滚动控件,这样无论是否显示列标题,滚动都能正常工作。
'Scroll the listview when close to the top or bottom
Dim HeaderOffset As Integer
If Me.View = Windows.Forms.View.Details Then
HeaderOffset = Me.TopItem.GetBounds(ItemBoundsPortion.Entire).Top
If e.Y <= HeaderOffset + Me.Font.Height / 1.5 Then
intScrollDirection = 0
tmrLVScroll.Enabled = True
ElseIf e.Y >= Me.ClientSize.Height - Me.Font.Height / 1.5 Then
intScrollDirection = 1
tmrLVScroll.Enabled = True
Else
tmrLVScroll.Enabled = False
End If
这是一个非常简单的实现,所以没有什么复杂的。没有花哨的代码,一切都很直接,而这正是我所偏好的,因为这样“未文档化的功能”就更少了。我还应该指出,项目在索引值方面确实会重新排序,无论是在哪种视图(大图标、列表、详细信息等);但是,项目在列表和详细信息视图之外的ListView
中不会被正确重绘,所以它们看起来没有改变,直到视图被更改然后改回来(或者也许是如果所有项目都被重新加载)。由于我只需要详细信息视图,所以我没有深入研究,但是如果您想在“大图标”视图中重新排序项目,这是一个很好的起点。我纠正了原始文章中其他视图的插入条显示方式。感谢mav.northwind的原始发布。希望这对大家有所帮助。
由于时间限制,我计划不为此提供支持,因此不打算发布新更新。请按原样使用——但如果您对修复“大图标”和其他视图重新排序后的显示更新有任何建议,我相信有人会乐于听到。感谢大家!
历史
- 2009年3月3日 - 首次发布。