Как добавить тысячи элементов в связанную коллекцию без блокировки GUI

У меня есть настройка, где потенциально тысячи элементов (думаю, 3000-5000) будут добавлены в ObservableCollection , привязанные к некоторому визуальному интерфейсу. В настоящее время процесс их добавления довольно медленный (около 4 секунд / 1000 элементов), и, конечно же, GUI не отвечает за это время. Каков хороший метод обработки перемещения сразу нескольких элементов в коллекцию, не беспокоясь о блокировке системы? Я посмотрел на DispatcherTimer но я не уверен, предоставит ли он все, в чем я нуждаюсь.

Другой вопрос: есть ли что-то, что я могу сделать, чтобы ускорить создание этих объектов, так что не требуется так много времени, чтобы добавить их в коллекцию? В настоящее время я использую их следующим образом: Collection.Add(new Item()) Будет ли генерировать элементы заранее, в фоновом streamе, вероятно, уменьшить время, необходимое для добавления их заметной суммой?

Изменить: виртуализация невозможна. Требования определяют WrapPanel вид WrapPanel , поэтому отображение фактически представляет собой ListBox с шаблоном ItemsPanel

Edit2: Согласно секундомеру, узкое место фактически помещает элементы в мой ObservableCollection . Я попробую изменить этот тип коллекции и сделать свое собственное уведомление, чтобы убедиться, что это значительно ускоряет его.

Edit3: Так ответ в одном месте – я решил эту проблему (с помощью снизу), создав class, который наследуется от ObservableCollection . Этот class сделал две вещи: разоблачить метод добавления коллекций за один раз и добавил способность подавлять событие CollectionChanged . С этими изменениями время, затрачиваемое на добавление 3000 предметов, составляет примерно 0,4 секунды (улучшение на 97%). Эта ссылка описывает реализацию этих изменений.

Вы сказали 1000, поэтому я буду придерживаться только этого номера.

IIRC, наблюдаемая коллекция имеет небольшой недостаток – если вы добавляете элементы один за другим, он уведомляет об этом один раз за каждый элемент. Это означает, что у вас 1000 уведомлений для 1000 элементов, а stream пользовательского интерфейса будет работать со смертельной скоростью, чтобы не отставать от перерисовки экрана.

Вам нужно перерисовать как можно скорее? Может быть, вы можете заказать дополнения? Разделите 1000 предметов на несколько упакованных из 100 предметов или немного больше пакетов из 50 или 20 предметов. Затем вместо того, чтобы поместить все элементы один за другим, поместите их в пакеты. Но будьте осторожны: вы должны использовать некоторые методы, такие как AddRange, реализованные самим compilationом, а не LINQ, иначе вы снова будете иметь одну по одну вставку. Если вы найдете такой метод, он должен значительно сократить количество событий, потому что сбор должен поднять событие Changed только один раз на вызов AddRange.

Если наблюдаемая коллекция не имеет AddRange, либо используйте другую коллекцию, либо напишите ее самостоятельно, вероятно, будет достаточно оболочки. objective состоит в том, чтобы НЕ повышать событие «Изменено» при каждом добавлении (), но после разумного подсчета их или, может быть, просто пропустить рейз. Изменено при добавлении предметов и повышении Изменено через определенные промежутки времени? Это было бы особенно полезно, если ваши данные «текут» бесконечно с постоянной скоростью.

Конечно, при таком количестве пунктов, которые выходят на экран, вы можете так же хорошо себя вести при рендеринге. Если ваши ItemTemplates сложны, 1000 объектов раз 1000 экземпляров визуальных слоев / свойств могут просто убить пользователя. Вы упростили ItemTemplates до минимума?

Последнее: рассмотрите возможность использования виртуализации StackPanels как ItemPanels в ItemsControl / ListBoxes. Это может значительно уменьшить объем памяти и количество элементов, нарисованных в один момент времени. Это не обязательно поможет в количестве или событиях, которые могут возникнуть, но это может сильно помочь при создании сложных шаблонов элементов!

Изменить: вы используете ObservableCollection, поэтому я предположил WPF / Silverlight .. обновить вопрос, если это неверно

По этой причине привязка WPF поддерживает параллелизм. Попробуйте установить Binding.IsAsync в true. К тому же.

  • Не используйте ObservableCollection , это медленно для этого, потому что каждый раз, когда элемент добавляется, он вызывает события. Используйте что-то быстрее, например List и поднимите уведомление об изменении свойств после добавления всех ваших элементов.
  • Предварительно создайте свои элементы в фоновом streamе, а затем вставьте их в свою коллекцию.
  • Проверьте другие части кода, чтобы увидеть, есть ли раздувание и обрезать.

Еще одна вещь, которую вы можете попробовать: подclass ObservableCollection и сделать его поддержкой массовой загрузки (AddRange). Вот статья: AddRange и ObservableCollection

По просьбе, вот как я решил эту проблему. Я начал с создания classа, который наследуется от ObservableCollection . Этот class сделал две вещи – разоблачить метод для добавления целых коллекций сразу и добавил возможность подавлять событие CollectionChanged . С этими изменениями время, затрачиваемое на добавление 3000 предметов, составляет примерно 0,4 секунды (улучшение на 97%). Эта ссылка описывает реализацию этих изменений.

для второго вопроса, если в вашем графическом интерфейсе вы используете технологию WPF, вы можете увеличить производительность с помощью VirualizingStackPanel, позволяя создавать только видимые элементы