I\'m trying to build a simple music player with a ListBox playlist. When adding audio files to the playlist, it first fills the ListBox with the filenames and then (on a sep
Nice repro code, I had no trouble diagnosing the source of the problem. It is a feature, not a bug. Press the arrow down key several times, then scroll the list. Note that it doesn't jump back now.
What's going on here is that list box automatically scrolls the item with the focus back into view when it gets updated. This is normally desirable behavior, you cannot turn it off. Workarounds, like selecting the item you're updating, isn't going to be pretty when you update the list like this, it is going to flicker badly. Maybe virtual mode, I didn't try it.
ListView doesn't have this behavior, consider using it instead. Use View = List or Details.
It might be prudent to disable any painting of the Listbox when doing the updates. Use ListBox.BeginUpdate()
and then update the entries, when done, invoke ListBox.EndUpdate()
. This should ensure that no refreshes occurs during the update.
You should also ensure that you do not refresh the ListBox from a thread either as cross-threading is dis-allowed, and the runtime will barf with a message saying that 'Cross Threading Exception' has occurred.
Use the ListBox's BeginInvoke(...)
method to get around the cross threading issue. See here on the MSDN on how this is done.
Yes, .BeginUpdate() is a good solution:
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Timer1.Start()
End Sub
Dim ix As Integer
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
ix = ListBox1.TopIndex
Label1.Text = ListBox1.TopIndex 'get most top displayed in the listbox
ListBox1.BeginUpdate() 'do not refresh during update
ListBox1.Items.Clear() 'do updates
For i = 1 To 100
ListBox1.Items.Add(i.ToString & "." & Int((101) * Rnd()).ToString)
Next
ListBox1.TopIndex = ix 'set the top item to be displayed
ListBox1.EndUpdate() 'refresh the listbox
End Sub
Private Sub VScrollBar1_Scroll(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ScrollEventArgs) _
Handles VScrollBar1.Scroll
VScrollBar1.Maximum = ListBox1.Items.Count
ListBox1.TopIndex = VScrollBar1.Value ' link another scrollbar if you want
Label2.Text = VScrollBar1.Value
End Sub
End Class
The code speaks by himself. A timer is generating random number. The numbers are populated in the List Box. Before the update just read the current Top Index of the List Box. During the update switch off the rendering by Begin Update. Then restore the Top Index and call End Update.
I put an extra Scroll Bar, linked to the List Box.