我正在尝试将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并立即开始显示某些内容。 有没有更好的方法来获得类似的行为,可能会缩短总的操作时间?
答案 0 :(得分:1)
在后台线程中加载所有数据,并在完成更新列表框的itemssource时。并且不要忘记在列表框中将Virtualization设置为true。
答案 1 :(得分:0)
耗时的操作是枚举您的ShellContainer
并创建数千个ShellObject
。 ListBox
不是问题。
当您将IEnumerable
设置为ItemControl
的来源时,我认为它首次显示时会从枚举器中创建内部列表,这就是为什么它在显示之前冻结了两分钟任何东西。
这里没有很多选择:
创建一个List<ShellObject>
并将其设置为ListBox
的来源。它并不快,但至少您可以向用户显示“正在加载,请稍候”消息。
将列表加载到另一个线程中(与您一样)并在加载时显示项目。随着时间的推移,这个名单会“增长”,这有点奇怪。
找到一种方法将ShellContainer
包装在实现IList
的类中。为此,您需要能够在ShellContainer
类(我不知道“Windows API代码包”)中的给定索引处获取项目。如果您将此作为ListBox
的来源并启用了虚拟化,则只会加载显示的ShellObject
,并且会快速顺利。