将项目添加到ListView控件时,UI会冻结

时间:2014-08-11 11:34:24

标签: c# .net winforms

我需要在我正在加载内容时更新UI ,并且我已经阅读并被告知BackgroundWorker是Windows窗体中作业的正确“工具”桌面应用。

所以现在我想知道为什么我的用户界面会在ListView Control更新时冻结,因为每个项目都会添加到其中。

private void Form1_Shown(object sender, EventArgs e)
{
    if (library.Songs != null)
    {
        loader.Enabled = true;
        worker.RunWorkerAsync();
    }
}

private void worker_DoWork(object sender, DoWorkEventArgs e)
{
    int songCount = 0;
    foreach (Song song in library.Songs)
    {
        songs.Add(song);
        worker.ReportProgress(songCount++);
    }
}

private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    list.Items.Add(songs[e.ProgressPercentage].Artist.Name);
    list.Update(); // This line is not the culprit. Removing it has no affect on the freezing.
    loader.Enabled = false;
}

private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // Hooray.
}

为什么我的用户界面会冻结,如何阻止它?我认为使用BackgroundWorker的重点在于,当我们正在做的事情时,血腥的UI不会冻结?!

更新

我有一个理论认为这种情况正在发生,因为有很多文件被加载,因此发生了ReportProgress(song)的调用过多,因此UI更新被留在队列中等待Progress调用光洁度。

那么,如果是这样的话,我怎么能把它全部分开,以便它一次处理一定比例的歌曲呢?

更新

Form1.cs中:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using Microsoft.Xna.Framework.Media;

    namespace Play
    {
        public partial class Form1 : Form
        {
            public MediaLibrary library = new MediaLibrary();
            public static List<Song> songs = new List<Song>();

            public Form1()
            {
                InitializeComponent();
            }

            public void TestPlay()
            {
                list.BeginUpdate();

                var itemsToAdd = library.Songs
                            .Select(x => new ListViewItem(x.Artist.Name))
                            .ToArray();

                list.Items.AddRange(itemsToAdd);

                list.EndUpdate();
            }

            private void Form1_Shown(object sender, EventArgs e)
            {
                TestPlay();
            }
        }
}

1 个答案:

答案 0 :(得分:3)

您的BackgroundWorker用法并没有带来太多好处(在此上下文中)。它只是将Song添加到集合中,并要求UI线程将歌曲添加到ListView

我建议您使用ListView.BeginUpdateEndUpdate方法,并在UI线程中填充列表。你可以完全抛弃那些没有增加任何价值的BackgroundWorker

否则,您需要添加项目的创建和数组,然后调用ListViewItems.AddRange,该var itemsToAdd = library.Songs .Select(x => new ListViewItem(x.Artist.Name)) .ToArray(); listView.Items.AddRange(itemsToAdd); 已针对一次添加多个元素进行了优化。

{{1}}