C# 将大IEnumerable设置为ListBox.ItemSource的最佳方法
我正在尝试使用Microsoft.Windows.APICodePack.Shell.ShellContainer作为ListBox的ItemsSource,通过ListBox.ItemTemplate显示每个子对象(ShellObject)的缩略图和名称。 当ShellContainer引用一个非常大的文件夹(比如超过1000个文件)时,问题就出现了:如果我简单地声明C# 将大IEnumerable设置为ListBox.ItemSource的最佳方法,c#,wpf,listbox,windows-api-code-pack,C#,Wpf,Listbox,Windows Api Code Pack,我正在尝试使用Microsoft.Windows.APICodePack.Shell.ShellContainer作为ListBox的ItemsSource,通过ListBox.ItemTemplate显示每个子对象(ShellObject)的缩略图和名称。 当ShellContainer引用一个非常大的文件夹(比如超过1000个文件)时,问题就出现了:如果我简单地声明 ShellContainer source=ShellObject.FromParsingName(@"C:\MyFo
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);
}
}
class-AsyncSourceFiller
{
私有可观测采集源;
私有容器路径;
私人控股母公司;
私人物品;
公共AsyncSourceFiller(ObservableCollection源、ShellContainer路径、控件父级)
{
this.source=源;
this.path=path;
this.parent=parent;
}
填空
{
foreach(路径中的ShellObject对象)
{
项目=obj;
parent.Dispatcher.Invoke(新操作(添加));
睡眠(4);
}
}
私有void Add()
{
来源.添加(项目);
}
}
然后通过
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();
observetecollection source=新的observetecollection();
listBox1.ItemsSource=源;
ShellContainer路径=ShellObject.FromParsingName(@“C:\MyFolder”):
AsyncSourceFiller=新的AsyncSourceFiller(源、路径、此);
螺纹th=新螺纹(填料填充);
th.IsBackground=true;
th.Start();
这比前一种方法需要更多的时间,但不会冻结UI并立即开始显示某些内容。
有没有更好的方法来获得类似的行为,可能会缩短总操作时间?在后台线程中加载所有数据,并在完成列表框的更新项源时加载。不要忘记在列表框中将Virtualization设置为true。耗时的操作是枚举
ShellContainer
并创建数千个ShellObject
<代码>列表框不是问题所在
当您将IEnumerable
设置为ItemControl
的源时,我认为它会在第一次显示枚举数时创建一个内部列表,这就是为什么它会在显示任何内容之前冻结两分钟
您在这里没有很多选项:
- 自己创建一个
,并将其设置为列表
的源。它不会更快,但至少可以向用户显示“正在加载,请稍候”消息列表框
- 在另一个线程中加载列表(与您一样),并在加载时显示项目。随着时间的推移,这个列表会“增长”,这有点奇怪
- 找到一种方法,将您的
包装在实现shell容器
的类中。为此,您需要能够在IList
类(我不知道“Windows API代码包”)中的给定索引处获取一个项。如果您将其用作ShellContainer
列表框的源,并且启用了虚拟化,则只会加载显示的
s,并且它将快速平滑外壳对象