在更新时防止框滚动到顶部 [英] Preventing ListBox scrolling to top when updated

查看:119
本文介绍了在更新时防止框滚动到顶部的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想建立一个简单的音乐播放器的列表框播放列表。当添加音频文件到播放列表中,它首先填满了文件名,然后(在一个单独的线程)ListBox中提取ID3数据,并用正确的艺术家将覆盖文件名 - 标题信息(很像Winamp的)

$。 b
$ b

不过,虽然列表框正在更新,它的unscrollable,因为它总是跳转到每个项目的覆盖顶部。



任何方式防止这种



编辑:结果
的代码:

 公共Form1中()
{
//此处省略一些初始化代码

&的BindingList LT; TAG_INFO>专辑曲目=新的BindingList< TAG_INFO>();

//播放列表
this.playlist =新System.Windows.Forms.ListBox();
this.playlist.Location =新System.Drawing.Point(12,12);
this.playlist.Name =播放列表;
this.playlist.Size =新System.Drawing.Size(229,316);
this.playlist.DataSource =曲目列表;
}

私人无效playlist_add_Click(对象发件人,EventArgs五)
{
//初始化打开文件对话框
打开文件对话框OPD =新的OpenFileDialog();
opd.Filter =音乐(* .WAV,* .MP3,* .FLAC)| * .WAV; * MP3; |(*。*)* FLAC所有文件| *。*;
opd.Title =选择音乐;
opd.Multiselect = TRUE;

//打开打开文件对话框
如果(DialogResult.OK == opd.ShowDialog())
{

//添加打开的文件到播放列表
。对于(INT I = 0; opd.FileNames.Length I标记; ++ I)
{
如果(File.Exists(opd.FileNames [I]))
{
trackList.Add(新TAG_INFO(opd.FileNames [I]));
}
}

//初始化BackgroundWorker的
BackgroundWorker的_bw =新的BackgroundWorker();
_bw.WorkerReportsProgress = TRUE;
_bw.DoWork + =新DoWorkEventHandler(thread_trackparser_DoWork);
_bw.ProgressChanged + =新ProgressChangedEventHandler(_bw_ProgressChanged);

//开始ID3提取
_bw.RunWorkerAsync();
}

}

无效thread_trackparser_DoWork(对象发件人,DoWorkEventArgs E)
{
BackgroundWorker的_bw =发件人为BackgroundWorker的;

的for(int i = 0; I< trackList.Count ++ I)
{
//通行证提取标签信息,以_bw_ProgressChanged线程安全的播放列表条目更新
_bw.ReportProgress(0,新的对象[2] {我,BassTags.BASS_TAG_GetFromFile(曲目[I] .filename)});
}
}

无效_bw_ProgressChanged(对象发件人,ProgressChangedEventArgs E)
{
对象[] =拆箱作为e.UserState对象[];

曲目[(int)的装箱[0]] =(无盒装[1]作为TAG_INFO);
}



EDIT2:结果
更简单的测试案例:结果
尝试向下滚动而不选择一个项目。该列表框更改将滚动再次顶

 使用系统;使用System.Windows.Forms的
;

命名空间WindowsFormsApplication1
{
公共Form1类:表格
{
私人System.ComponentModel.IContainer成分= NULL;

保护覆盖无效的Dispose(BOOL处置)
{
如果(处置和放大器;及(成分= NULL)!)
{
组分。的Dispose();
}
base.Dispose(处置);
}

私人无效的Ini​​tializeComponent()
{
this.components =新System.ComponentModel.Container();
this.listBox1 =新System.Windows.Forms.ListBox();
this.timer1 =新System.Windows.Forms.Timer(this.components);
this.SuspendLayout();

// listBox1中
this.listBox1.FormattingEnabled = TRUE;
this.listBox1.Location =新System.Drawing.Point(0,0);
this.listBox1.Name =listBox1中;
this.listBox1.Size =新System.Drawing.Size(200,290);

//定时器1
this.timer1.Enabled = TRUE;
this.timer1.Tick + =新System.EventHandler(this.timer1_Tick);

// Form1中
this.AutoScaleDimensions =新System.Drawing.SizeF(6F,13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize =新System.Drawing.Size(200,290);
this.Controls.Add(this.listBox1);
this.Name =Form1的;
this.Text =Form1的;
this.ResumeLayout(假);
}

私人System.Windows.Forms.ListBox listBox1中;
私人System.Windows.Forms.Timer定时器1;

公共Form1中()
{
的InitializeComponent();

的for(int i = 0; I< 45;我++)
listBox1.Items.Add(I)
}

INT tickCounter = -1;

私人无效timer1_Tick(对象发件人,EventArgs五)
{
如果(++ tickCounter> 44)tickCounter = 0;
listBox1.Items [tickCounter] =((int)的listBox1.Items [tickCounter])+ 1;
}
}

静态类节目
{
[STAThread]
静态无效的主要()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(假);
Application.Run(新Form1中());
}
}
}


解决方案

尼斯摄制的代码,我没有任何麻烦,诊断问题的根源。这是一个特点,不是一个错误。按方向键上下数次,然后滚动列表。请注意,它不跳回来了。



这是怎么回事是当它被更新的列表框中自动滚动为重点的项目回视图。这通常是可取的行为,则无法将其关闭。变通方法,比如选择您要更新的项目,不会在更新列表这样,它会闪烁严重是相当。也许虚拟模式,我没有尝试。



ListView控件没有这种行为,可以考虑使用它来代替。使用View =列表或详细信息。


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

解决方案

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆