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



我正在尝试使用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 并立即开始显示某些内容。有没有更好的方法来获得类似的行为,可能缩短总操作时间?

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

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

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

您在这里没有太多选择:

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

  • 在另一个线程中加载列表(就像您一样(并在加载项目时显示项目。这有点奇怪,因为列表会随着时间的推移而"增长"。

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

相关内容

  • 没有找到相关文章

最新更新