Асинхронное добавление в ObservableCollection (или альтернативу)
вот что у меня
- список с ItemsSource установлен в ObservableCollection<T>
- где T-мой пользовательский класс, представляющий файл, содержащий только 2 DependencyProperties: Filename и ThumbnailPath.
- В listbox также есть пользовательский DataTemplate определен, чтобы красиво отображать изображение и имя файла под ним.
целью списка является отображение видеофайлов в текущей папке (выбранной в TreeView) с миниатюрами (сгенерированными асинхронно; не является частью этого проблема.)
поэтому, когда я меняю папку в TreeView, ObservableCollection очищается и заполняется снова, что автоматически отражается в элементах списка.
вот проблема: пользовательский интерфейс перестает отвечать на запросы и обновление занимает до нескольких секунд. Опять же, миниатюры здесь не имеют значения (я попытался отключить их). Я думаю что занимает больше всего времени, это построение 50-100 экземпляров моего пользовательского класса и их визуального представление-оно должно инициализировать объект изображения для каждого из них. Но это только мое предположение - не могли бы вы подтвердить или исключить такую возможность?
Я начинаю думать ObservableCollection не может путь пойти здесь, так как из того, что я читал и немного из того, что я пробовал, нет возможности добавлять элементы асинхронно, по крайней мере, если эти элементы DependencyObjects. Я попытался создать экземпляры класса с помощью BackgroundWorker и добавить их в коллекцию в Обработчик событий ProgressChanged, но он выдает исключение (некоторая проблема с потоком vs dependencyobjects).
есть что-то, что я упускаю? Или мне было бы лучше просто отказаться от ObservableCollection и написать старый добрый асинхронный цикл for, чтобы добавить элементы?
2 ответов
поскольку ObservableCollection
привязан к UI, поэтому он генерируется в потоке UI, поэтому любые дальнейшие обновления (удалить/добавить/очистить) должны быть в том же потоке UI. Он не разрешает обновления из другого потока.
однако то, что вы можете сделать, это создать insance вашего класса (или все трудоемкие операции в фоновом потоке), и как только вы закончите, добавьте объект в ObservableCollection, используя что диспетчер do помещает операцию в связанный с ней поток. Следовательно, элемент всегда добавляется в поток пользовательского интерфейса, но может быть создан в фоновом потоке. вот несколько ссылок, которые могут вам начать работу - обновление от BW и здесьDispatcher
из- App.Current.Dispatcher.BeginInvoke((Action)delegate()
{
observableCollection.Add(instanceOfYourClass);
});
с .net 4.5 вы можете использовать EnableCollectionSynchronization
object lockObj = new object();
BindingOperations.EnableCollectionSynchronization(yourObservableCollection, lockObj);