2010-05-22 99 views
4

我想用ListBox播放列表構建一個簡單的音樂播放器。將音頻文件添加到播放列表時,首先用文件名填充列表框,然後(在單獨的線程上)提取ID3數據並用正確的藝術家 - 標題信息覆蓋文件名(很像Winamp)。防止列表框滾動到頂部時更新

但是當ListBox被更新時,它是不可滾動的,因爲它總是跳到每個項目覆蓋的頂部。

任何方式來防止這種情況?

編輯:
代碼:

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

您可以發表一些代碼。它的更新方式可能與問題有關。 – 2010-05-22 18:15:52

+0

當然。已添加代碼。 – WDZ 2010-05-22 19:35:20

+0

添加了更簡單的代碼來演示相同的問題。 – WDZ 2010-05-22 20:25:33

回答

4

好的repro代碼,我沒有麻煩診斷問題的根源。這是一個功能,而不是一個錯誤。按向下箭頭鍵幾次,然後滾動列表。請注意,它現在不會跳回來。

這裏發生了什麼是該列表框自動將焦點的項目滾動到更新時的視圖中。這通常是可取的行爲,您不能關閉它。變通方法,比如選擇你正在更新的項目,當你像這樣更新列表時,變得不會很漂亮,它會閃爍不定。也許虛擬模式,我沒有嘗試它。

ListView沒有這種行爲,請考慮使用它。使用視圖=列表或詳細信息。

+0

好的詳盡答案。謝謝! – WDZ 2010-05-22 22:06:49

+0

完美的作品!還使用http://stackoverflow.com/questions/442817擺脫更新期間的閃爍。 – WDZ 2010-05-23 01:27:58

1

在執行更新時禁用任何對Listbox的繪製可能是明智的做法。使用ListBox .BeginUpdate()然後更新條目,完成後調用ListBox .EndUpdate()。這應確保在更新過程中不會發生刷新。

您還應該確保您不會從線程中刷新ListBox,或者因爲跨線程被禁用,並且運行時會用一條消息說明發生了「跨線程異常」。

使用列表框的BeginInvoke(...)方法來解決交叉線程問題。請參閱MSDN上的here瞭解如何完成此操作。

相關問題