Prevent ListBox scrolling when updating

I am trying to create a simple ListBox list player music player. When adding audio files to the playlist, it first populates the ListBox with file names, and then (in a separate stream) extracts ID3 data and overwrites the file names with the correct artist name information - Title (like Winamp).

But while the ListBox is being updated, it is not being scanned, since it always jumps to the top on each overwrite element.

How to prevent this?

EDIT:
The code:

public Form1() { //Some initialization code omitted here BindingList<TAG_INFO> trackList = new BindingList<TAG_INFO>(); // The Playlist this.playlist = new System.Windows.Forms.ListBox(); this.playlist.Location = new System.Drawing.Point(12, 12); this.playlist.Name = "playlist"; this.playlist.Size = new System.Drawing.Size(229, 316); this.playlist.DataSource = trackList; } private void playlist_add_Click(object sender, EventArgs e) { //Initialize OpenFileDialog OpenFileDialog opd = new OpenFileDialog(); opd.Filter = "Music (*.WAV; *.MP3; *.FLAC)|*.WAV;*.MP3;*.FLAC|All files (*.*)|*.*"; opd.Title = "Select Music"; opd.Multiselect = true; //Open OpenFileDialog if (DialogResult.OK == opd.ShowDialog()) { //Add opened files to playlist for (int i = 0; opd.FileNames.Length > i; ++i) { if (File.Exists(opd.FileNames[i])) { trackList.Add(new TAG_INFO(opd.FileNames[i])); } } //Initialize BackgroundWorker BackgroundWorker _bw = new BackgroundWorker(); _bw.WorkerReportsProgress = true; _bw.DoWork += new DoWorkEventHandler(thread_trackparser_DoWork); _bw.ProgressChanged += new ProgressChangedEventHandler(_bw_ProgressChanged); //Start ID3 extraction _bw.RunWorkerAsync(); } } void thread_trackparser_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker _bw = sender as BackgroundWorker; for (int i = 0; i < trackList.Count; ++i) { //Pass extracted tag info to _bw_ProgressChanged for thread-safe playlist entry update _bw.ReportProgress(0,new object[2] {i, BassTags.BASS_TAG_GetFromFile(trackList[i].filename)}); } } void _bw_ProgressChanged(object sender, ProgressChangedEventArgs e) { object[] unboxed = e.UserState as object[]; trackList[(int)unboxed[0]] = (unboxed[1] as TAG_INFO); } 

EDIT2:
A much simpler test case:
Try scrolling down without selecting an item. The changing ListBox will scroll up again.

 using System; using System.Windows.Forms; namespace WindowsFormsApplication1 { public class Form1 : Form { private System.ComponentModel.IContainer components = null; protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.listBox1 = new System.Windows.Forms.ListBox(); this.timer1 = new System.Windows.Forms.Timer(this.components); this.SuspendLayout(); // listBox1 this.listBox1.FormattingEnabled = true; this.listBox1.Location = new System.Drawing.Point(0, 0); this.listBox1.Name = "listBox1"; this.listBox1.Size = new System.Drawing.Size(200, 290); // timer1 this.timer1.Enabled = true; this.timer1.Tick += new System.EventHandler(this.timer1_Tick); // Form1 this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(200, 290); this.Controls.Add(this.listBox1); this.Name = "Form1"; this.Text = "Form1"; this.ResumeLayout(false); } private System.Windows.Forms.ListBox listBox1; private System.Windows.Forms.Timer timer1; public Form1() { InitializeComponent(); for (int i = 0; i < 45; i++) listBox1.Items.Add(i); } int tickCounter = -1; private void timer1_Tick(object sender, EventArgs e) { if (++tickCounter > 44) tickCounter = 0; listBox1.Items[tickCounter] = ((int)listBox1.Items[tickCounter])+1; } } static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } } 
+4
source share
2 answers

Good reprogramming code, I was unable to diagnose the source of the problem. This is a feature, not a mistake. Press the down arrow key several times, then scroll through the list. Please note that it does not bounce back.

What happens here is that the list box automatically scrolls the item when focus returns to view when it is updated. Usually this behavior is desirable; you cannot disable it. Workarounds, such as selecting the item you are updating, will not be pleasant when you refresh the list like this, it will flicker badly. Perhaps virtual mode, I have not tried.

ListView does not have this behavior, try using it. Use View = List or Details.

+4
source

It may be wise to disable any Listbox coloring when performing updates. Use ListBox .BeginUpdate() and then refresh the entries, when done, call ListBox .EndUpdate() . This should ensure that there will be no update during the update.

You must also ensure that you are not updating the ListBox from the stream, since cross-streaming is not allowed, and the runtime forbids a message indicating that “Cross-thread Exclusion” has occurred.

Use the ListBox BeginInvoke(...) method to get around the cross-threading issue. See here on MSDN for how this is done.

+1
source

Source: https://habr.com/ru/post/1310616/


All Articles