vbAccelerator - Contents of code file: CancellableEditPopupVB_EditableListBox.vb

Namespace vbAccelerator.Components.Controls

    ''' <summary>
    ''' A derived ListBox control allows items to be edited in place
    ''' </summary>
    Public Class EditableListBox
        Inherits ListBox

        Private m_readOnly As Boolean = False
        Private lastSelectedIndex As Integer = -1
        Private WithEvents popupNotifier As PopupCancelNotifier = Nothing
        Private WithEvents txtPopupEdit As TextBox = Nothing


        ''' <summary>
        ''' Gets/sets whether the ListBox can be edited or not.
        ''' </summary>
        Public Property IsReadOnly() As Boolean
            Get
                Return m_readOnly
            End Get
            Set(ByVal Value As Boolean)
                m_readOnly = Value
            End Set
        End Property

        ''' <summary>
        ''' Starts editing the specified item.
        ''' </summary>
        ''' <param name="index">0-mybased index of item to edit</param>
        Public Sub StartItemEdit(ByVal index As Integer)

            ' Stop editing if we are:
            EndTextEdit(False)

            ' Select the item:
            Me.lastSelectedIndex = index
            Me.SelectedIndex = index
            ' is the item visible?

            ' start editing:
            StartTextEdit()
        End Sub

        ''' <summary>
        ''' Ends editing if we are editing, setting whether to commit
        ''' changes or not.
        ''' </summary>
        Public Sub EndItemEdit(ByVal commit As Boolean)
            If (txtPopupEdit.Visible) Then
                EndTextEdit(commit)
            End If
        End Sub

        ''' <summary>
        ''' Raises the <see cref="SelectedIndexChanged"/>
        ''' event and performs processing to ensure items can be edited
        ''' </summary>
        ''' <param name="e">Not used</param>
        Protected Overrides Sub OnSelectedIndexChanged(ByVal e As EventArgs)
            MyBase.OnSelectedIndexChanged(e)
            lastSelectedIndex = MyBase.SelectedIndex
        End Sub

        ''' <summary>
        ''' Raises the <see cref="MouseDown"/>
        ''' event and starts editing in place if appropriate.
        ''' </summary>
        ''' <param name="e">Mouse information associated with the event.</param>
        Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
            MyBase.OnMouseDown(e)

            If ((Not (m_readOnly) And (e.Button = MouseButtons.Left))) Then
                If Not (txtPopupEdit.Visible) Then
                    If ((MyBase.SelectedIndex = lastSelectedIndex) And
                     (lastSelectedIndex > -1)) Then
                        StartTextEdit()
                    End If
                End If
            End If

        End Sub

        ''' <summary>
        ''' Responds to the <see cref="PopupCancelNotifier"/> <see
         cref="PopupCancel"/>
        ''' event.
        ''' </summary>
        ''' <param name="sender">PopupCancelNotifier object which sent the
         event</param>
        ''' <param name="e"><see cref="PopupCanceEventArgs"/> describing the
         cancel event.</param>
        Private Sub popupNotifier_PopupCancel(ByVal sender As Object, ByVal e
         As
         CancellableEditPopupVB.vbAccelerator.Components.Controls.PopupCancelEve
        ntArgs) Handles popupNotifier.PopupCancel
            EndTextEdit(True)
        End Sub


        ''' <summary>
        ''' Responds to the <see cref="KeyDown"/> event on the popup edit text
        ''' control to allow end and cancel edit on Return and Escape keys
        ''' </summary>
        ''' <param name="sender">TextBox which sent the event</param>
        ''' <param name="e"><see cref="KeyEventArgs"/> describing the key
         event.</param>

        Private Sub txtPopupEdit_KeyDown(ByVal sender As Object, ByVal e As
         System.Windows.Forms.KeyEventArgs) Handles txtPopupEdit.KeyDown
            Select Case (e.KeyData)
                Case Keys.Return
                    ' end editing:
                    EndTextEdit(True)
                    e.Handled = True

                Case Keys.Escape
                    ' cancel editing:
                    EndTextEdit(False)
                    e.Handled = True
            End Select
        End Sub


        ''' <summary>
        ''' Internal method to start editing.
        ''' </summary>
        Private Sub StartTextEdit()
            Me.Focus()

            txtPopupEdit.Text = MyBase.SelectedItem
            If (txtPopupEdit.Text.Length > 0) Then
                txtPopupEdit.SelectionStart = 0
                txtPopupEdit.SelectionLength = txtPopupEdit.Text.Length
            End If
            txtPopupEdit.Tag = MyBase.SelectedItem
            Dim bounds As Rectangle = GetListBoxItemBounds()
            txtPopupEdit.Location = Bounds.Location
            txtPopupEdit.Size = Bounds.Size
            txtPopupEdit.Visible = True
            txtPopupEdit.BringToFront()
            txtPopupEdit.Focus()

            popupNotifier.StartTracking(txtPopupEdit)

        End Sub

        ''' <summary>
        ''' Gets the bounding rectangle of the selected item in the ListBox
        ''' </summary>
        ''' <returns><see cref="System.Drawing.Rectangle"/> containing the
        ''' bounds of the item on screen.</returns>
        Protected Overridable Function GetListBoxItemBounds() As Rectangle
            Dim itemHeight As Integer = MyBase.ItemHeight
            Dim selectedIndex As Integer = MyBase.SelectedIndex
            Dim top As Integer = (selectedIndex - MyBase.TopIndex) * itemHeight
            Return New Rectangle(0, top, MyBase.ClientRectangle.Width,
             itemHeight)
        End Function

        ''' <summary>
        ''' Internal method to end text editing and optionally commit changes.
        ''' </summary>
        ''' <param name="commit">Whether changes should be committed or
         not.</param>
        Private Sub EndTextEdit(ByVal commit As Boolean)
            If (commit) Then
                MyBase.Items(MyBase.SelectedIndex) = txtPopupEdit.Text
            End If
            txtPopupEdit.Visible = False
            popupNotifier.StopTracking()
        End Sub


        ''' <summary>
        ''' Constructs a new instance of the editable ListBox
        ''' </summary>
        Public Sub New()

            MyBase.New()
            popupNotifier = New PopupCancelNotifier()

            txtPopupEdit = New System.Windows.Forms.TextBox()
            ' 
            ' txtPopupEdit
            ' 
            Me.txtPopupEdit.AcceptsReturn = True
            Me.txtPopupEdit.BorderStyle = System.Windows.Forms.BorderStyle.None
            Me.txtPopupEdit.Location = New System.Drawing.Point(128, 216)
            Me.txtPopupEdit.Name = "txtPopupEdit"
            Me.txtPopupEdit.Multiline = True
            Me.txtPopupEdit.Size = New System.Drawing.Size(144, 14)
            Me.txtPopupEdit.TabIndex = 0
            Me.txtPopupEdit.Text = ""
            Me.txtPopupEdit.Visible = False

            Dim ctl(1) As Control
            ctl(1) = txtPopupEdit
            Me.Controls.AddRange(ctl)
        End Sub
    End Class

End Namespace