genespos genespos - 9 months ago 59 Question cancel SelectedIndexChanged and reselect previous item

I have a

and when a different item is selected some data need to be deleted.

To avoid accidentally deleting, I've added a confirm message on

This way, data are cancelled only after confirmation.

My problem is: How can I also avoid changing of selected item when not confirmed?

(I wish to mantain the previous selected index)

I noticed that I can't use

I also know that I could store actual value in a global variable and use it to restore previous value but I'm asking for a better solution (if it's possible).


At the time, I'm storing the Index in a form level variable and I'm using a boolean to avoid executing the event twice. Below you can see my code:

Private Sub CBox_AmType_SelectedIndexChanged(sender As Object, e As EventArgs) Handles CBox_AmType.SelectedIndexChanged
If DontRunSelChange Then
DontRunSelChange = False
Exit Sub
End If
'...some code
Dim OkCanc As DialogResult = MessageBox.Show("Are you sure?", "Changing confirmation",
MessageBoxButtons.OKCancel, MessageBoxIcon.Question)
If OkCanc = vbCancel Then
DontRunSelChange = True 'This to avoid running twice
CBox_AmType.SelectedIndex = AmType_Index
Exit Sub
End If
'...some code
End sub


The following is my attempt using Plutonix code:

Private Sub ComboBoxEx1_SelectedIndexChanging(sender As Object, e As SelectedIndexChangingEventArgs) Handles ComboBoxEx1.SelectedIndexChanging
Dim SN As DialogResult = MessageBox.Show("Are you sure?", "Changing confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
If SN = DialogResult.No Then
e.Cancel = True
Exit Sub
End If
Me.Lbl_Text.Text = Me.ComboBoxEx1.SelectedItem.ToString
End Sub

But the event is fired twice, called by the row:

MyBase.SelectedIndex = MyBase.Items.IndexOf(selectedObject)

Answer Source

This should do most of what you want. It subclasses ComboBox to add a new event which fires before the SelectedIndexChanged event. If you cancel, then that event does not fire.

Public Class SelectedIndexChangingEventArgs
    Inherits EventArgs

    Public Property Cancel As Boolean = False
    Public Property NewIndex As Int32 = -1

    Friend Sub New(index As Int32)
        NewIndex = index
    End Sub
End Class

Public Class ComboBoxEx
    Inherits ComboBox

    Private selectedObject As Object = Nothing

    Public Event SelectedIndexChanging(sender As Object, 
                            e As SelectedIndexChangingEventArgs)

    Public Sub New()
    End Sub

    Protected Overrides Sub OnSelectedIndexChanged(e As EventArgs)
        Dim evArgs As New SelectedIndexChangingEventArgs(MyBase.SelectedIndex)
        RaiseEvent SelectedIndexChanging(Me, evArgs)

        If evArgs.Cancel Then
            If selectedObject IsNot Nothing Then
                MyBase.SelectedIndex = MyBase.Items.IndexOf(selectedObject)
                MyBase.SelectedIndex = -1
            End If
            Return       ' do not fire Changed event
        End If

        selectedObject = MyBase.Items(MyBase.SelectedIndex)
    End Sub
End Class

It just internalizes the logic you probably already have, but if there are more than one "cancel-able" controls on the form, you wont have to have multiple index tracking variables. Maybe that is simpler.


Private Sub ComboBoxEx1_SelectedIndexChanging(sender As Object,
          e As SelectedIndexChangingEventArgs) Handles ComboBoxEx1.SelectedIndexChanging
    If ComboBoxEx1.Items(e.NewIndex).ToString.Contains("o") Then
        e.Cancel = True
    End If
End Sub

Since the Items collection can be modified, a simple LastIndex variable may not be enough - it could refer to the wrong item after something is added or removed. This tracks the last object selected and tries to find it in the current list.

It also works with a DataSource, but there are probably a number of other situations to be accounted for.