Preventing ListBox scrolling to top when updated

Posted by WDZ on Stack Overflow See other posts from Stack Overflow or by WDZ
Published on 2010-05-22T18:04:49Z Indexed on 2010/05/22 21:10 UTC
Read the original article Hit count: 213

Filed under:
|
|

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 separate thread) extracts the ID3 data and overwrites the filenames with the correct Artist - Title information (much like Winamp).

But while the ListBox is being updated, it's unscrollable, as it always jumps to the top on every item overwrite.

Any way 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:
Much simpler test case:
Try scrolling down without selecting an item. The changing ListBox will scroll to the top 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());
        }
    }
}

© Stack Overflow or respective owner

Related posts about c#

Related posts about winforms