异步添加到ObservableCollection(或替代)

时间:2022-09-12 08:30:37

Here's what I have - a ListBox with an ItemsSource set to a ObservableCollection<T> - where T is my custom class representing a file, containing just 2 DependencyProperties: Filename and ThumbnailPath. - The listbox also has a custom DataTemplate defined, in order to nicely display a image and filename under it.

这就是我所拥有的 - 一个ListBox,其ItemsSource设置为ObservableCollection - 其中T是我的自定义类,表示一个文件,只包含2个DependencyProperties:Filename和ThumbnailPath。 - 列表框还定义了自定义DataTemplate,以便在其下很好地显示图像和文件名。

The purpose of the listbox is to display video files in the current folder (selected in a TreeView), with thumbnails (generated asynchronously; not part of this problem).

列表框的目的是显示当前文件夹中的视频文件(在TreeView中选择),缩略图(异步生成;不是此问题的一部分)。

So when I change the folder in the TreeView, the ObservableCollection is cleared and filled up again, which is automatically reflected in the the ListBox items.

因此,当我更改TreeView中的文件夹时,ObservableCollection将被清除并再次填充,这将自动反映在ListBox项目中。

Here's the problem: The UI becomes unresponsive and it takes up to several seconds to update. Again, thumbnails do not have significance here (I tried disabling them). I think what takes the most time is the construction of 50-100 instances of my custom class, and their visual representation - it has to initialize an Image object for each one. But it's just my guess - could you please confirm or exclude the possibility?

问题在于:UI变得无法响应,更新需要几秒钟。同样,缩略图在这里没有意义(我尝试禁用它们)。我认为花费最多时间的是构建我自定义类的50-100个实例及其可视化表示 - 它必须为每个实例初始化一个Image对象。但这只是我的猜测 - 你能否确认或排除这种可能性?

I'm beginning to think ObservableCollection may not the way to go here, since from what I read and a little from what I tried, there's no way to add items asynchronously, at least if these items are DependencyObjects. I tried creating my class instances with a BackgroundWorker and adding them to the collection in the ProgressChanged event handler, but it throws an exception (some threading vs dependencyobjects problem).

我开始认为ObservableCollection可能不是这里的方式,因为根据我的阅读和我尝试的内容,没有办法异步添加项目,至少如果这些项目是DependencyObjects。我尝试使用BackgroundWorker创建我的类实例,并将它们添加到ProgressChanged事件处理程序中的集合中,但它会抛出异常(某些线程与dependencyobjects问题)。

Is there something that I'm missing? Or would I be better off by simply ditching the ObservableCollection and writing a good old async for loop to add the items?

有什么东西我不见了吗?或者通过简单地抛弃ObservableCollection并编写一个好的旧异步for循环来添加项目,我会更好吗?

2 个解决方案

#1


12  

Since your ObservableCollection is bound to UI hence it gets generated on UI thread so any further updates (delete/add/clear) have to be on the same UI thread. It doesn't allow updates from another thread.

由于您的ObservableCollection绑定到UI,因此它在UI线程上生成,因此任何进一步的更新(删除/添加/清除)必须位于同一UI线程上。它不允许来自另一个线程的更新。

However, what you can do is create insance of your class (or all time consuming operation on background thread) and once you are done, add the object in ObservableCollection using Dispatcher of your UI thread like this -

但是,你可以做的是创建你的类的insance(或在后台线程上进行所有耗时的操作),完成后,使用你的UI线程的Dispatcher在ObservableCollection中添加对象,如下所示 -

App.Current.Dispatcher.BeginInvoke((Action)delegate()
                          {
                              observableCollection.Add(instanceOfYourClass);
                          });

What Dispatcher do is put the operation on its associated thread. Hence, the item will always be added on UI thread but can be created in background thread.

Dispatcher所做的是将操作放在其关联的线程上。因此,该项将始终添加到UI线程上,但可以在后台线程中创建。

Here are few links which might get you going - Updating from BW and other one here

这里有一些链接可能会让你去 - 从BW和其他一个更新

#2


6  

With .net 4.5 you can use EnableCollectionSynchronization

使用.net 4.5,您可以使用EnableCollectionSynchronization

 object lockObj = new object();
        BindingOperations.EnableCollectionSynchronization(yourObservableCollection, lockObj);

#1


12  

Since your ObservableCollection is bound to UI hence it gets generated on UI thread so any further updates (delete/add/clear) have to be on the same UI thread. It doesn't allow updates from another thread.

由于您的ObservableCollection绑定到UI,因此它在UI线程上生成,因此任何进一步的更新(删除/添加/清除)必须位于同一UI线程上。它不允许来自另一个线程的更新。

However, what you can do is create insance of your class (or all time consuming operation on background thread) and once you are done, add the object in ObservableCollection using Dispatcher of your UI thread like this -

但是,你可以做的是创建你的类的insance(或在后台线程上进行所有耗时的操作),完成后,使用你的UI线程的Dispatcher在ObservableCollection中添加对象,如下所示 -

App.Current.Dispatcher.BeginInvoke((Action)delegate()
                          {
                              observableCollection.Add(instanceOfYourClass);
                          });

What Dispatcher do is put the operation on its associated thread. Hence, the item will always be added on UI thread but can be created in background thread.

Dispatcher所做的是将操作放在其关联的线程上。因此,该项将始终添加到UI线程上,但可以在后台线程中创建。

Here are few links which might get you going - Updating from BW and other one here

这里有一些链接可能会让你去 - 从BW和其他一个更新

#2


6  

With .net 4.5 you can use EnableCollectionSynchronization

使用.net 4.5,您可以使用EnableCollectionSynchronization

 object lockObj = new object();
        BindingOperations.EnableCollectionSynchronization(yourObservableCollection, lockObj);