将BIG IEnumerable设置为ListBox.ItemSsource的最佳方法

时间:2012-05-07 07:09:21

标签: c# wpf listbox windows-api-code-pack

我正在尝试将Microsoft.Windows.APICodePack.Shell.ShellContainer用作ListBox的ItemsSource,通过ListBox.ItemTemplate显示每个子项(ShellObject)缩略图和名称。 当ShellContainer引用一个非常大的文件夹(比如超过一千个文件)时会出现问题:如果我只是声明

    ShellContainer source=ShellObject.FromParsingName(@"C:\MyFolder") as ShellContainer:
    listBox1.ItemsSource=source.GetEnumerator();

它冻结UI两到三分钟,然后一次显示ShellContainer的内容。 我发现最好的解决方法是创建一个像这样的

的异步填充类
class AsyncSourceFiller
{
    private ObservableCollection<ShellObject> source;
    private ShellContainer path;
    private Control parent;
    private ShellObject item;

    public AsyncSourceFiller(ObservableCollection<ShellObject> source, ShellContainer path, Control parent)
    {
        this.source = source;
        this.path = path;
        this.parent = parent;
    }

    public void Fill()
    {
        foreach (ShellObject obj in path)
        {
            item = obj;
            parent.Dispatcher.Invoke(new Action(Add));
            Thread.Sleep(4);
        }
    }

    private void Add()
    {
        source.Add(item);
    }
}

然后通过

调用它
    ObservableCollection<ShellObject> source = new ObservableCollection<ShellObject>();
    listBox1.ItemsSource = source;
    ShellContainer path = ShellObject.FromParsingName(@"C:\MyFolder"):
    AsyncSourceFiller filler = new AsyncSourceFiller(source, path, this);
    Thread th = new Thread(filler.Fill);
    th.IsBackground = true;
    th.Start();

这比以前的方式花费更多时间,但不会冻结UI并立即开始显示某些内容。 有没有更好的方法来获得类似的行为,可能会缩短总的操作时间?

2 个答案:

答案 0 :(得分:1)

在后台线程中加载所有数据,并在完成更新列表框的itemssource时。并且不要忘记在列表框中将Virtualization设置为true。

答案 1 :(得分:0)

耗时的操作是枚举您的ShellContainer并创建数千个ShellObjectListBox不是问题。

当您将IEnumerable设置为ItemControl的来源时,我认为它首次显示时会从枚举器中创建内部列表,这就是为什么它在显示之前冻结了两分钟任何东西。

这里没有很多选择:

  • 创建一个List<ShellObject>并将其设置为ListBox的来源。它并不快,但至少您可以向用户显示“正在加载,请稍候”消息。

  • 将列表加载到另一个线程中(与您一样)并在加载时显示项目。随着时间的推移,这个名单会“增长”,这有点奇怪。

  • 找到一种方法将ShellContainer包装在实现IList的类中。为此,您需要能够在ShellContainer类(我不知道“Windows API代码包”)中的给定索引处获取项目。如果您将此作为ListBox的来源并启用了虚拟化,则只会加载显示的ShellObject,并且会快速顺利。