How to prevent Listbox jumps to ítem?

2019-08-31 13:05发布

问题:

Suppose that in a WinForms I have a Listbox with multiselect enabled, listbox contains 50 items and only the first item of the listbox is selected...

...Then if I select (using SetSelected method) the last item then the listbox will jump to bottom (together with the vertical scroll) to show me that item.

I just want that the listbox stays in the position that it was, while I use SetSelected to select other items, I don't want the listbox moving up and down everytime.

So how I can prevent the Listbox and the listbox v. scrollbar to jump to ítem when I use SetSelected method? (in both directions up or down)

I hope that maybe I could use a function of WinAPI to do this.

回答1:

You can try using the TopIndex to set the top visible index like this:

//Use this ListBox extension for convenience
public static class ListBoxExtension {
   public static void SetSelectedWithoutJumping(this ListBox lb, int index, bool selected){
     int i = lb.TopIndex;
     lb.SetSelected(index, selected);
     lb.TopIndex = i;
   }
}
//Then just use like this
yourListBox.SetSelectedWithoutJumping(index, true);

You can also try defining some method to set selected for a collection of indices and use the BeginUpdate and EndUpdate to avoid flickering:

 public static class ListBoxExtension {
   public static void SetMultiSelectedWithoutJumping(this ListBox lb, IEnumerable<int> indices, bool selected){
     int i = lb.TopIndex;
     lb.BeginUpdate();
     foreach(var index in indices)
        lb.SetSelected(index, selected);
     lb.TopIndex = i;
     lb.EndUpdate();
   }
}   
//usage
yourListBox.SetMultiSelectedWithoutJumping(new List<int>{2,3,4}, true);

NOTE: You can also use the BeginUpdate and EndUpdate in the SetSelectedWithoutJumping, however as I said, if you have to select multi-indices together, implementing some extension method like SetMultiSelectedWithoutJumping is better and more convenient (we just use 1 pair of BeginUpdate and EndUpdate).



回答2:

I just want to share the VB.NET version:

#Region " [ListBox] Select item without jump "

    ' [ListBox] Select item without jump
    '
    ' Original author of code is "King King"
    ' Url: stackoverflow.com/questions/19479774/how-to-prevent-listbox-jumps-to-item
    '
    ' // By Elektro H@cker
    '
    ' Examples :
    '
    ' Select_Item_Without_Jumping(ListBox1, 50, ListBoxItemSelected.Select)
    '
    ' For x As Integer = 0 To ListBox1.Items.Count - 1
    '    Select_Item_Without_Jumping(ListBox1, x, ListBoxItemSelected.Select)
    ' Next

    Public Enum ListBoxItemSelected
        [Select] = 1
        [Unselect] = 0
    End Enum

    Public Shared Sub Select_Item_Without_Jumping(lb As ListBox, index As Integer, selected As ListBoxItemSelected)
        Dim i As Integer = lb.TopIndex ' Store the selected item index
        lb.BeginUpdate() ' Disable drawing on control
        lb.SetSelected(index, selected) ' Select the item
        lb.TopIndex = i ' Jump to the previous selected item
        lb.EndUpdate() ' Eenable drawing
    End Sub

#End Region