2010-05-22 5 views
4

Я пытаюсь создать простой музыкальный плеер с списком воспроизведения ListBox. При добавлении аудиофайлов в список воспроизведения он сначала заполняет ListBox именами файлов, а затем (в отдельном потоке) извлекает данные ID3 и перезаписывает имена файлов с правильной информацией о названии Artist - Title (подобно Winamp).Предотвращение ListBox, прокручивающегося наверху при обновлении

Но в то время как ListBox обновляется, он не поддается проверке, так как он всегда перескакивает на вершину на каждом элементе overwrite.

Любой способ предотвратить это?

EDIT:
Код:

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:
Намного проще тест:
Попробуйте прокрутки вниз без выбора элемента. Сменяющийся ListBox снова переместится вверх.

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()); 
     } 
    } 
} 
+0

Можете ли вы опубликовать какой-либо код, пожалуйста. То, как оно обновляется, может быть связано с проблемой. –

+0

Конечно. Добавлен код. – WDZ

+0

Простой код для демонстрации той же проблемы. – WDZ

ответ

4

Хороший репродуцирующий код, мне не удалось диагностировать источник проблемы. Это особенность, а не ошибка. Несколько раз нажмите клавишу со стрелкой вниз, затем прокрутите список. Обратите внимание, что он не отскакивает назад.

Что здесь происходит, это то, что окно списка автоматически прокручивает элемент, когда фокус возвращается в режим просмотра, когда он обновляется. Обычно это поведение желательно, вы не можете его отключить. Обходные пути, такие как выбор элемента, который вы обновляете, не будут приятными, когда вы обновите список, как это, он будет мерцать плохо. Возможно, виртуальный режим, я не пробовал.

В ListView не было такого поведения, подумайте над этим. Используйте View = List или Details.

+0

Хороший исчерпывающий ответ. Благодаря! – WDZ

+0

Работает отлично! Также используется http://stackoverflow.com/questions/442817, чтобы избавиться от мерцания во время обновления. – WDZ

1

Возможно, было бы разумно отключить любую окраску списка при выполнении обновлений. Используйте ListBox .BeginUpdate(), а затем обновите записи, когда это будет сделано, вызовите ListBox .EndUpdate(). Это должно гарантировать, что во время обновления обновления не возникает.

Вы также должны убедиться, что вы не обновляете ListBox из потока, так как перекрестная потоковая передача разрешена, а среда выполнения запустит сообщение с сообщением о том, что произошло «Исключение перекрестных потоков».

Используйте метод ListBox BeginInvoke(...), чтобы обойти проблему сквозной резьбы. См. here в MSDN о том, как это делается.

Смежные вопросы