ListBoxにドラッグアンドドロップ関連の処理を書き加えることで、ListBox内に表示されているアイテムをドラッグアンドドロップで移動できるように拡張したListBoxクラスを紹介する。
Public Class DragDropListBox
Inherits ListBox
''' <summary>
''' ドラッグアンドドロップされるアイテムのデータ
''' </summary>
Private Structure DragDropItemData
Public Sub New(ByVal index As Integer)
m_Index = index
End Sub
Private m_Index As Integer
Public ReadOnly Property Index() As Integer
Get
Return m_Index
End Get
End Property
End Structure
''' <summary>
'''
''' </summary>
Public Sub New()
MyBase.New()
Me.AllowDrop = True
End Sub
' ドラッグアンドドロップの開始点
Private mouseDownPoint As Point
' ドラッグするアイテムのインデックス
Private dragDropSourceItemIndex As Integer
''' <summary>
''' MouseDown
''' </summary>
Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
If (e.Button And MouseButtons.Left) = MouseButtons.Left Then
' ドラッグアンドドロップの開始点
mouseDownPoint = New Point(e.X, e.Y)
dragDropSourceItemIndex = Me.IndexFromPoint(e.X, e.Y)
Else
mouseDownPoint = Point.Empty
dragDropSourceItemIndex = ListBox.NoMatches
End If
MyBase.OnMouseDown(e)
End Sub
''' <summary>
''' MouseUp
''' </summary>
Protected Overrides Sub OnMouseUp(ByVal e As MouseEventArgs)
mouseDownPoint = Point.Empty
MyBase.OnMouseUp(e)
End Sub
''' <summary>
''' MouseMove
''' </summary>
Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)
If (e.Button And MouseButtons.Left) = MouseButtons.Left Then
' ドラッグアンドドロップの範囲にあるか否かをチェックする
Dim dragBound As Rectangle = New Rectangle(e.X - SystemInformation.DragSize.Width \ 2, e.Y - SystemInformation.DragSize.Height \ 2, SystemInformation.DragSize.Width, SystemInformation.DragSize.Height)
If Not dragBound.Contains(mouseDownPoint) AndAlso dragDropSourceItemIndex <> ListBox.NoMatches Then
' ドラッグアンドドロップ用のデータを作成
Dim itemData As DragDropItemData = New DragDropItemData(dragDropSourceItemIndex)
' アイテムをドラッグアンドドロップする
Dim effects As DragDropEffects = Me.DoDragDrop(itemData, DragDropEffects.Move)
End If
End If
MyBase.OnMouseMove(e)
End Sub
''' <summary>
''' DragEnter
''' </summary>
Protected Overrides Sub OnDragEnter(ByVal drgevent As DragEventArgs)
If drgevent.Data.GetDataPresent(GetType(DragDropItemData)) Then
drgevent.Effect = DragDropEffects.Move
Else
drgevent.Effect = DragDropEffects.None
End If
MyBase.OnDragEnter(drgevent)
End Sub
''' <summary>
''' DragDrop
''' </summary>
Protected Overrides Sub OnDragDrop(ByVal drgevent As DragEventArgs)
If drgevent.Data.GetDataPresent(GetType(DragDropItemData)) Then
' 入れ替え先のインデックス
Dim targetIndex As Integer = Me.IndexFromPoint(Me.PointToClient(New Point(drgevent.X, drgevent.Y)))
If targetIndex = ListBox.NoMatches Then targetIndex = Me.Items.Count - 1
' ドラッグアンドドロップするアイテムのデータを取得
Dim itemData As DragDropItemData = DirectCast(drgevent.Data.GetData(GetType(DragDropItemData)), DragDropItemData)
' アイテムを入れかえる
Dim temp As Object = Me.Items(itemData.Index)
Me.Items(itemData.Index) = Me.Items(targetIndex)
Me.Items(targetIndex) = temp
' 入れ替えたアイテムを選択する
Me.SelectedItem = temp
End If
MyBase.OnDragDrop(drgevent)
End Sub
End Class