Alex
Alex

Reputation: 828

avoid list view selected index changed firing twice

Quite a simple question, when the selected index of a list view is changed, the event fires twice, once for deselection and a second time to select the next item.

I need to use the event when selecting or deselecting at different times however whan deselecting only to reselect a moment later it makes half my ui flash from enabled being on to off and back on again, it also causes a fair bit of code to run so I just need a way of avoiding the deselection firing if it was another item that was clicked and not blank space (for deselection)

Dave R said to use a 100ms timer here : Am I missing something with my ListView selection event handling which sounds like it would work but seems quite untidy or generally a bad way of doing it.

My only other idea was to use the click event and then find the item at the location? but I'd rather not go to the hassle

thanks in advance!

-EDIT-

I've just thought that the click event would fire first so I could set a flag that skips selection index changed code if the click event happened on an item and then resets the flag after it's been used therefore skipping the deselection? I'll have a look now but again doesnt feel like a very efficient or easy way of doing something that sounds quite simple?

Upvotes: 5

Views: 9412

Answers (4)

Kwadjo Nyante
Kwadjo Nyante

Reputation: 9

Just check in the SelectedIndexChanged event whether the focused item is null and exit.

ListView^ item = listView1-> FocusedItem;   //get selected item
if (item == nullptr){return;)  // this line exits when deselection event fires
String^ data1 = Convert::ToString (  item-> SubItems [0]    );   // get your data from columns like so
MessageBox::Show (data1);  // display

note that you could grab data under several columns by changing index provided in SubItems And using timers and delays will just incur overhead especially with large databases causing your application to slow Code in visual C++ .NET but the same theory applies for C# and others

Enjoy!!

Upvotes: -1

Preston777
Preston777

Reputation: 21

i just tried another solution which is potentially without any delay, it worked for me:

    If ListView1.Items(ListView1.FocusedItem.Index).Selected = False Then
        'This is the deselected value
        MsgBox("Deselected: " & ListView1.Items(ListView1.FocusedItem.Index).SubItems(0).Text)
    Else
        'This is the new selected value
        MsgBox("Selected: " & ListView1.Items(ListView1.FocusedItem.Index).SubItems(0).Text)
    End If

Upvotes: 2

Michael Wetzig
Michael Wetzig

Reputation: 35

The following solution works even with a delay of 1 ms. To be sure it works probably you can choose a higher delay, 10 ms for example, but a delay of 100 ms will make it a bit laggy on selecting "nothing". Here's the C#-Code:

public class FixedListView : ListView
{
    private Timer _ItemSelectionChangedTimer = new Timer();
    private Timer _SelectedIndexChangedTimer = new Timer();

    private ListViewItemSelectionChangedEventArgs _ItemSelectionChangedEventArgs;
    private EventArgs _SelectedIndexChangedEventArgs;

    public FixedListView()
    {
        this._ItemSelectionChangedTimer.Interval = 1;
        this._SelectedIndexChangedTimer.Interval = 1;

        this._ItemSelectionChangedTimer.Tick += (sender, e) =>
        {
            this.OnItemSelectionChanged(this._ItemSelectionChangedEventArgs);
            this._ItemSelectionChangedEventArgs = null;
        };
        this._SelectedIndexChangedTimer.Tick += (sender, e) =>
        {
            this.OnSelectedIndexChanged(this._SelectedIndexChangedEventArgs);
            this._SelectedIndexChangedEventArgs = null;
        };
    }

    protected override void OnItemSelectionChanged(ListViewItemSelectionChangedEventArgs e)
    {
        if (this._ItemSelectionChangedTimer.Enabled)
        {
            this._ItemSelectionChangedTimer.Stop();
            base.OnItemSelectionChanged(e);
        }
        else
        {
            this._ItemSelectionChangedEventArgs = e;
            this._ItemSelectionChangedTimer.Start();
        }
    }

    protected override void OnSelectedIndexChanged(EventArgs e)
    {
        if (this._SelectedIndexChangedTimer.Enabled)
        {
            this._SelectedIndexChangedTimer.Stop();
            base.OnSelectedIndexChanged(e);
        }
        else
        {
            this._SelectedIndexChangedEventArgs = e;
            this._SelectedIndexChangedTimer.Start();                
        }
    }
}

And here is the VB-Code:

Public Class FixedListBox

Inherits ListView

Public Sub New()

    Me._ItemSelectionChangedTimer.Interval = 1
    Me._SelectedIndexChangedTimer.Interval = 1

    AddHandler Me._ItemSelectionChangedTimer.Tick, _
        Sub(sender, e)
            Me.OnItemSelectionChanged(Me._ItemSelectionChangedEventArgs)
            Me._ItemSelectionChangedEventArgs = Nothing
        End Sub

    AddHandler Me._SelectedIndexChangedTimer.Tick, _
        Sub(sender, e)
            Me.OnSelectedIndexChanged(Me._SelectedIndexChangedEventArgs)
            Me._SelectedIndexChangedEventArgs = Nothing
        End Sub

End Sub

Private _ItemSelectionChangedTimer As New Timer()
Private _SelectedIndexChangedTimer As New Timer()

Private _ItemSelectionChangedEventArgs As ListViewItemSelectionChangedEventArgs
Private _SelectedIndexChangedEventArgs As EventArgs

Protected Overrides Sub OnItemSelectionChanged(e As ListViewItemSelectionChangedEventArgs)

    If Me._ItemSelectionChangedTimer.Enabled Then

        Me._ItemSelectionChangedTimer.Stop()
        MyBase.OnItemSelectionChanged(e)

    Else

        Me._ItemSelectionChangedEventArgs = e
        Me._ItemSelectionChangedTimer.Start()

    End If

End Sub

Protected Overrides Sub OnSelectedIndexChanged(e As EventArgs)

    If Me._SelectedIndexChangedTimer.Enabled Then

        Me._SelectedIndexChangedTimer.Stop()
        MyBase.OnSelectedIndexChanged(e)

    Else

        Me._SelectedIndexChangedEventArgs = e
        Me._SelectedIndexChangedTimer.Start()

    End If

End Sub

End Class

You can use the control like a normal ListView but SelectedIndexChanged and ItemSelectionChanged will fire only once.

Have fun...

Upvotes: 0

stuartd
stuartd

Reputation: 73243

Use the ItemSelectionChanged event instead - the ListViewItemSelectionChangedEventArgs can tell you which item caused it to fire, and whether it's selected or not.

Upvotes: 4

Related Questions